Changing the title of status menu items while the status menu is open is causing crashes in my Cocoa application
Okay, this question is just getting more and more complex, so I'm going to scratch it completely and start over. I managed to create a very basic Cocoa app that demonstrates my issue.
So here's the problem:
Inside of a thread, I'm setting the title of a menu item in my application's status bar menu. When the application tries to change the title of the menu item, and I have the menu open, most of the time it works, but some of the times it crashes the application.
Here is the full code of the sample app:
MenubarFailAppDelegate.h
#import <Cocoa/Cocoa.h>
@interface MenubarFailAppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
IBOutlet NSMenuItem *menuItem;
int currentDelay;
}
@end
MenubarFailAppDelegate.m
#import "MenubarFailAppDelegate.h"
@implementation MenubarFailAppDelegate
- (id)init {
self = [super init];
if (self != nil)
{
currentDelay = 0;
}
return self;
}
- (void)awakeFromNib {
// Create status menu item
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];
[statusItem setMenu:statusMenu];
[statusItem setTitle:@"Fail"];
[statusItem setHighlightMode:YES];
currentDelay = 3;
[NSThread detachNewThreadSelector:@selector(changeStatusItemTitleLoopThread)
toTarget:self
withObject:nil];
}
- (void)changeStatusItemTitleLoopThread {
NSAu开发者_高级运维toreleasePool *pool = [[NSAutoreleasePool alloc] init];
while (currentDelay > 0) {
// Sleep for one second
NSDate *future = [NSDate dateWithTimeIntervalSinceNow:1];
[NSThread sleepUntilDate:future];
// Decrement current delay
currentDelay--;
}
NSLog(@"Setting menu item title");
[menuItem setTitle:@"lol cat"];
[pool release];
}
@end
And here is the crash report that appears when the program crashes after logging "Setting menu item title":
#0 0x7fff870f74c0 in HIStandardMenuView::FetchItemCache
#1 0x7fff870f6345 in HIStandardMenuView::GetOptimalSizeSelf
#2 0x7fff870f612b in HIView::GetOptimalSizeWithLimitsSelf
#3 0x7fff870f5fb5 in HIView::SendGetOptimalBounds
#4 0x7fff870f5edb in HIView::GetOptimalSize
#5 0x7fff870f5dc1 in HandleCalculateMenuSize
#6 0x7fff8709b600 in MenuData::EventHandler
#7 0x7fff87093997 in DispatchEventToHandlers
#8 0x7fff87092ee6 in SendEventToEventTargetInternal
#9 0x7fff87092d57 in SendEventToEventTargetWithOptions
#10 0x7fff870f5b7a in _CalcMenuSizeOnDevice
#11 0x7fff8710811c in RecalcAndResizeMenu
#12 0x7fff8720efa6 in ResizeMenuArray
#13 0x7fff8720eff6 in ResizeOpenMenus
#14 0x7fff87093997 in DispatchEventToHandlers
#15 0x7fff87092ee6 in SendEventToEventTargetInternal
#16 0x7fff87092d57 in SendEventToEventTargetWithOptions
#17 0x7fff870c012a in ToolboxEventDispatcherHandler
#18 0x7fff87093d91 in DispatchEventToHandlers
#19 0x7fff87092ee6 in SendEventToEventTargetInternal
#20 0x7fff870b0ba9 in SendEventToEventTarget
#21 0x7fff870bdeed in AcquireEventFromQueue
#22 0x7fff870ba737 in ReceiveNextEventCommon
#23 0x7fff87104db8 in IsUserStillTracking
#24 0x7fff870f1a48 in TrackMenuCommon
#25 0x7fff87215ac9 in PopUpMenuSelectCore
#26 0x7fff87215dce in _HandlePopUpMenuSelection7
#27 0x7fff864d71c9 in _NSSLMPopUpCarbonMenu3
#28 0x7fff86706e71 in -[NSStatusBarButtonCell trackMouse:inRect:ofView:untilMouseUp:]
#29 0x7fff8640a4b5 in -[NSControl mouseDown:]
#30 0x7fff86324763 in -[NSWindow sendEvent:]
#31 0x7fff86707c10 in -[NSStatusBarWindow sendEvent:]
#32 0x7fff86259ee2 in -[NSApplication sendEvent:]
#33 0x7fff861f0922 in -[NSApplication run]
#34 0x7fff861e95f8 in NSApplicationMain
#35 0x100001499 in main at main.m:13
Making UI changes in threaded code is generally not recommended. Is there a compelling reason you need to change the menu titles in a thread? I'd recommend dispatching the actual change back to the main thread. You can do whatever calculation you need in the background thread and use performSelectorOnMainThread to make the actual change of the title.
精彩评论