Archive for the ‘Apple’ Category

Working without a nib, Part 5: Open Recent menu

Tuesday, July 10th, 2007

Judging from the search phrases in my referrer log and from posts to Apple’s mailing lists, quite a few people are interested in developing Cocoa applications without using nibs. I’ve heard the demand, and you’ll be pleased to learn that the wait is over. I have a sweet solution. Today I’m announcing a Cocoa nibless SDK. You can download the SDK immediately — from the web! Specifically, from my blog. Just load this web page in Safari and select Save As… from the File menu.

(Don’t worry about me. I hear that the Chairman of the Board has a sense of humor. I’m sure that these two large gentlemen at my door are here to convey his appreciation of my wit and to deliver an invitation to lunch.)

(No! No! Stop, please! Not the iPod too! Have mercy!)

At the end of Part 4 of this series, I suggested that we needed to call setValue:@"NSRecentDocumentsMenu" forKey:@"name" to set the Open Recent menu. This is why they call me “Good Ol’ Oftenwrong”. Luckily, if you have a document-based application, Cocoa will generously create an Open Recent menu for you. All you need to do is put a menu item with the action @selector(openDocument:) in pretty much any menu, and Open Recent will magically appear as the next item in the menu. Now that’s a sweet solution!

If you want an Open Recent menu for a non-document app, on the other hand, you need to use an ugly hack. Although it was clear that the NSMenu ivar _name is set to @"NSRecentDocumentsMenu" for the Open Recent menu in a standard Cocoa MainMenu.nib, I couldn’t get the menu to populate with recent items in my nibless app even after setting _name. By pure trial and error, I discovered that you have to call _setMenuName:@"NSRecentDocumentsMenu" rather than setValue:@"NSRecentDocumentsMenu" forKey:@"name". (It was a natural choice after trying setName: and _setName:, which are not implemented by NSMenu.) The method _setMenuName: does set the _name ivar, but apparently it does some other crucial stuff too. Perhaps it asks a favor of the iGodfather. Anyway, I’ve updated my Nibless Xcode project to demonstrate this behavior.

In summary, we have succeeded (by we I mean the royal we) in creating a Cocoa application with a full main menu but without any nib (and without any error messages). For this purpose we’ve had to call two private methods, -[NSApplication setAppleMenu:] and -[NSMenu _setMenuName:], as well as poseAsClass: to override +[NSBundle loadNibNamed:owner:]. Not bad. And it’s taken us less than two months to reproduce what Interface Builder can do in less than two seconds. Isn’t this fun? The hardest part is finished, though. From now on, it’s just smooth sailing, on the Good Ship of Pyaray.

Oh, one more thing. Let’s dance! Anyway you want it.

Working without a nib, Part 4: setAppleMenu

Sunday, June 17th, 2007

Wow, this series already has four parts. It’s entering Rocky territory, having already surpassed Rambo. If I continue much longer I’ll be typecast — (NSNib *)jeff — and no one will remember my work on Vienna or my poignant portrayal of Hamlet (in the community theater production of Guys and Dolls).

A comment by Jack Nutting inspired me to run some additional tests. As the-programmer-currently-known-as-j-o-a-r (formerly known as horse-spear) mentioned in another comment, you can use the method -[NSApplication setAppleMenu:] to set the application menu. The catch is that it’s been removed from the public API and is no longer declared in NSApplication.h. To call the method, you have to declare it yourself in a category:


@interface NSApplication (NiblessAdditions)
-(void) setAppleMenu:(NSMenu *)aMenu;
@end

You could also avoid the need for a category declaration by using [NSApp performSelector:NSSelectorFromString(@"setAppleMenu:") withObject:aMenu].

My tests revealed that AppKit does call -[NSApplication setAppleMenu:] when loading the main menu from a nib, so it appears that this method is no more (or less) fragile than the technique I discovered in Part 2. As far as I can tell, setAppleMenu: sets the title of the menu to @"Apple" and the name of the menu to @"NSAppleMenu", which is why my technique is functionally equivalent. (The method -[NSApplication setMainMenu:] sets the name of the menu to @"NSMainMenu", so my [mainMenu setValue:@"NSMainMenu" forKey:@"name"] isn’t strictly necessary.) It’s a mystery why Apple ‘disappeared’ the method. Maybe it will magically return in a later operating system, with a long beard and a dark tan.

I’m not aware of a method, hidden or otherwise, to set the recent documents menu. Thus, my technique of calling [openRecentMenu setValue:@"NSRecentDocumentsMenu" forKey:@"name"] still seems necessary. Chasing around a little chicken, though, just seems unnecessary and not very mature.

Working without a nib, Part 5: No, 3!

Sunday, June 10th, 2007

For all you desperate souls waiting in line at the Moscone Center, and you more desperate souls waiting in line at MacRumors, take heart, because there’s something even more desperate than you — NSApplicationMain(). It’s so desperate to load a nib that it’ll take the first one it can find. When your application launches, NSApplicationMain() instantiates the NSPrincipalClass from your app’s Info.plist and calls +[NSBundle loadNibNamed:owner:] with the instance as the owner. This method in turn calls +[NSBundle bundleForClass:] with your NSPrincipalClass and -[NSBundle pathForResource:ofType:] with type @"nib". If your Info.plist contains no NSMainNibFile key, then the nib name and path arguments for those methods are nil. Why in the world would your Info.plist be missing NSMainNibFile? See Part 1 of this series. If that doesn’t answer the question, see Part 2. If that doesn’t answer the question, see Part 3.

When I set the NSPrincipalClass key to my custom NSApplication subclass, the corresponding bundle for that class is my app’s main bundle, so if there’s no nib in the bundle, the app fails to launch with the error, No NSMainNibFile specified in info dictionary, exiting. However, when I leave NSPrincipalClass as NSApplication, the corresponding bundle turns out to be /System/Library/Frameworks/AppKit.framework. If you send the message -[NSBundle pathForResource:nil ofType:@"nib"] to that bundle, it returns /System/Library/Frameworks/AppKit.framework/Resources/English.lproj/NSAlertPanel.nib, which is the first nib file in the English.lproj folder. As a consequence, NSApplicationMain() attempts to load NSAlertPanel.nib and set the file’s owner to your app’s NSApplication instance. That particular nib file contains several buttons with the action buttonPressed: targeted at the file’s owner, but unlike NSAlert, which is specified as the class of the file’s owner in the nib, NSApplication doesn’t implement buttonPressed:, so you get the error, Could not connect the action buttonPressed: to target of class NSApplication. Mystery solved! And I would have gotten away with it too, if it wasn’t for those meddling kids!

There are a number of ways to handle this problem. My preferred workaround, which I’ve implemented in the revised version of the Nibless project, is to set NSPrincipalClass to JJApplication, call [[JJBundle class] poseAsClass:[NSBundle class]] in main.m, and override an NSBundle method in JJBundle.m:


+(BOOL) loadNibNamed:(NSString *)aNibNamed owner:(id)owner {
    if (!aNibNamed && owner == NSApp) {
        // We're lying here. Don't load anything.
        return YES;
    } else {
        return [super loadNibNamed:aNibNamed owner:owner];
    }
}

We now return to our regularly scheduled WWDC speculation. (I predict that everyone in the audience will get a car.) If you are attending The Keynote on Monday, remember to bring plenty of Scooby snacks. If you’re playing the home game: every time Steve says “cool”, drink!

Working without a nib, Part 2: Also Also Wik

Monday, June 4th, 2007

I apologize for the fault in the subtitle. Those responsible have been sacked. What I intended to say was that I’ve discovered the Holy Grail of Cocoa hacks: how to create a functional Cocoa application without any nib. In Part 1 of this series, I suggested that you needed a nib for the main menu of the app; some would even argue that having a nib is the essence of a Cocoa app. It turns out that I was wrong, and some (they, the unspecified straw persons) were wrong too. I apologize for any faults in my previous post. Those responsible would be sacked, but those responsible for sacking have just been sacked.

As you may recall if you have a photographic memory or nothing better to do, the main problem with getting rid of nibs is setting the application menu. I had been using a minimal nib as a workaround, but now I have a reliable, though undocumented, solution to the problem. I came upon the solution by using gdb and JJApp (along with a herring) to override initWithCoder: while the main menu is loaded from a nib. The class NSMenu has a private ivar _name, declared in /System/Library/Frameworks/AppKit.framework/Headers/NSMenu.h, that is usually nil, but a few menus — including the application menu — have a string value for the ivar. Although there are no public accessors, we can set the value anyway through the magic of key-value coding. For example, I called setValue:@"NSMainMenu" forKey:@"name" on my main menu and setValue:@"NSAppleMenu" forKey:@"name" on my application menu. This must be done before the return of -[NSApplication finishLaunching], otherwise it will have no effect. I find applicationWillFinishLaunching: to be a good place to set your main menu.

Another caveat is that the old deleting-the-nib trick doesn’t work at all if you change NSPrincipalClass in Info.plist. When I set it to my NSApplication subclass, the app refuses to launch, complaining, No NSMainNibFile specified in info dictionary, exiting. Strangely, it works fine if I leave NSPrincipalClass alone and call [[JJApplication class] poseAsClass:[NSApplication class]] in main.m. A special treat is that Cocoa automatically adds the Special Characters item to the Edit menu at runtime. Thanks, Cocoa! You can see all of this yourself by downloading my sample Xcode project, Nibless. If you use my code in your app, I may sue you, or I may kiss you. In either case, it’s a risk you’ll have to take. (It!)

Despite the fact that my solution is for the most part unsupported by official API (consult the book of armaments!), there’s good reason to think that it’s stable and should survive Leopard at least. Apple is unlikely to remove an ivar from such an important class as NSMenu. More important, the value of the ivar seems to be the way that archived menus indicate their function to Cocoa and to Interface Builder, as reflected by the “Special Menus” setting in the Inspector. Try opening keyedobjects.nib with BBEdit, and you’ll see that the file is just a plist containing definitions of the objects in the nib.

In Part 5 of this series — sorry, Part 3 — I’ll investigate the cause of the log message Could not connect the action buttonPressed: to target of class NSApplication when launching without a nib. I’ll also attempt to populate the Open Recent menu. The Clear Menu item seems to work, but for some reason I can’t get items to appear in the menu. So, um, anything that you could do to help would be very helpful.

I’d like to end this post on a personal note. Many of my legions of fans have sent emails asking for more information about me: birth date, hobbies, pet peeves, dress size, etc. I prefer not to start a cult of personality, but I’ve decided that you, the heroes, deserve something. Thus, I’m going to share one particularly juicy tidbit. My favorite color is … blue. No, yellooooooooow!

Working without a nib, Part 1

Wednesday, May 16th, 2007

There are a number of reasons why you might want to build your application without a nib. As you may know, ‘nib’ is an acronym for no inspecting bindings. Anyone who uses version control (in other words, anyone except R.B.) can see in the diffs that nib files are rather opaque. The next Interface Builder, the one in Mac OS X 10.5 Leopard, may offer some improvements in this area, although I can’t really say yet. This is not to say that I’m under NDA. It’s not to say that I’m not under NDA either. I am in fact under NDA, so many NDA it makes my head spin. I can’t even say how many NDA. This is not to say that my NDA prevent me from saying how many NDA I’m under. I just don’t know. Anyway, I don’t have a Leopard seed. Even if I did have Leopard, which I don’t, it isn’t scheduled for release until October, and besides, many developers will still want to support Tiger at the very least for years to come. Thus, my topic is not necessarily obsolete at startup, unlike the computer you just bought.

It is indeed possible to to run a Cocoa application entirely without a nib: create a Cocoa application project in Xcode, delete MainMenu.nib, and remove the NSMainNibFile entry from Info.plist. (You do get the log error Could not connect the action buttonPressed: to target of class NSApplication.) You can allocate your own objects in main(), though you must do that before calling NSApplicationMain(), not after. (It’s too late, Jim, he’s dead already.) Remember, Jim, main.m is just another Objective-C source file. Objects that you allocate before NSApplicationMain() can even register to receive notifications such as NSApplicationDidFinishLaunching, so you can hook into the launching process and perform whatever setup you need.

For all practical purposes, however, you can’t really work without a nib. The problem is the main menu, or more specifically, the application menu. In a normal Cocoa application, the application menu is what would be returned by [[[NSApp mainMenu] itemAtIndex:0] submenu]. In MainMenu.nib of a default Xcode Cocoa application project, the application menu is the submenu for the item NewApplication. Actually, it doesn’t matter what the title is of this menu item, because regardless of how you set it in Interface Builder, Cocoa replaces the title at runtime with an empty string, and the name of the application boldly goes on the menu bar. The title of the application menu itself is Apple, which is highly misleading, considering that its left-side neighbor on the menu bar has an Apple icon at the top. Just to be clear, the Apple menu is not the menu with an Apple. Got it?

What prevents our nibless existence is that the application menu refuses to be set programmatically. If there is no main nib file or no main menu in the main nib, Cocoa creates an application menu automatically, and there appears to be no API to access it. You could create your own NSMenu with an NSMenuItem at index 0 having a submenu with the title @"Apple", but if you try to set it as the main menu with -[NSApplication setMainMenu:], all of your submenus, including your Apple menu, will appear to the right of the automatically generated application menu. Like a poor marksman, you’ll keep missing the target!

When faced with a no-win situation, what do we do? Cheat! My workaround to the problem is to keep MainMenu.nib in the Cocoa project but leave only the most minimal main menu possible. The Window can be deleted entirely, and in the MainMenu, delete everything except the NewApplication menu item and its submenu, which is listed as the Application Menu in the Inspector. The submenu’s menu items can be deleted. If you allow the main menu to come from the nib, then the Apple menu will automatically become part of -[NSApplication mainMenu], and you can populate it and the rest of the main menu yourself. The most elegant way of populating the main menu, in my opinion, would be to subclass NSApplication, set your subclass as NSPrincipalClass in Info.plist, call [self mainMenu] in your subclass awakeFromNib, and add items to the returned menu. (The NSPrincipalClass of your app needs to be a subclass of NSApplication, otherwise your app crashes on launch with a selector not recognized exception.)

In Part 2 of the series, I’ll attempt to add some functionality to my currently useless, empty app. My ongoing mission will be to explore the strange new world of life without (much of) a nib. It’s a difficult concept, perhaps not very logical, but we learn by doing.

The cat’s in the bag: Vienna 2.1.2

Saturday, April 7th, 2007

I’ve decided to adopt Apple’s practice of naming software releases after cats. Therefore, today I’m announcing Vienna 2.1.2 Sylvester. The release notes are here, and you can download it there. Please post bug reports and feature requests yonder. It’s basically just a minor, bug fix release to tide you over until Vienna 2.2 Morris. Sufferin’ succotash! Since Vienna is open source, we’ve had to write convoluted, unreadable code in order to hide the secret new features in Morris. Not for any other reason.

That’s all, folks!

Invoking errors

Sunday, April 1st, 2007

If I had to name my specialty as a developer, it would be error code. I’ve reached a point in my career where I can invoke errors almost instinctively. This post is about NSErrors, however, which differ from regular errors in one crucial respect: the more NSErrors in your app, the better. Yes, even when Apple makes errors, they’re appealing. This post is also about NSInvocations, which sound arcane, and they are. I use them, but I’m afraid of them … kind of like microwave ovens. I have no idea what’s going on inside, but they make good Cocoa. (Cat’s breath, charm of sleep and bath, thy omen of scratching.)

There will come a time, maybe not today, maybe not tomorrow, maybe not soon, maybe not for the rest of your life, but someday anyway, when you’ll want to use an NSError as an argument to an NSInvocation. Or maybe never, but you’ll certainly want to use a pointer to a pointer to an NSError. That’s an error’s cousin, once removed; they can marry in selected states. The standard pattern for handling errors with Cocoa methods is to directly return a BOOL indicating success or failure and to return ‘by reference’ (look that up in your Funk & Wagnalls) an NSError that provides additional information about the failure, e.g., You’re a loser, and who does your hair, Floyd the barber? If you call the method by name — heyJoe — you can just pass the address (&) of your NSError object as an argument to the method. What if you want the method to vary at runtime, though?

Suppose that your app needs to perform a series of disparate tasks, and each task requires error checking afterward to determine whether the series should continue. Using conventional methods, your code could become a winding mess. All roads lead to Rome, just not in a straight line. The more pleasant alternative, in my opinion, is to wrap up everything into NSInvocations at the beginning to store in an NSArray for iteration. And rather than having a monstrous error checking method with endless if else clauses, you could have an aptly named error checker corresponding to an individual task, just as in key-value coding you have an aptly named setter corresponding to the getter. For example, we have a sample error checking method:


-(BOOL) didSucceedAtJoe:(id)result error:(NSError **)error {
	BOOL didSucceed = result != nil;
	if (!didSucceed && error) {
		*error = [NSError errorWithDomain:@"MyErrorDomain" code:69 userInfo:nil];
	}
	return didSucceed;
}
	

Such a method would be invoked by a generic error checker:


-(BOOL) didSucceedAtTask:(NSDictionary *)taskInfo {
	BOOL didSucceed = NO;
	NSError * error = nil;
	NSInvocation * invocation = [self invocationForDidSucceedAtTaskWithName:[taskInfo objectForKey:@"name"]];
	if (invocation) {
		id result = [taskInfo objectForKey:@"result"];
		[invocation setArgument:&result atIndex:2];
		NSError ** errorPointer = &error;
		[invocation setArgument:&errorPointer atIndex:3];
		[invocation invokeWithTarget:self];
		[invocation getReturnValue:&didSucceed];
	}
	NSLog(@"error:%@", error);
	return didSucceed;
}
	

It’s crucial to the invocation that you declare, and thus allocate memory for, both NSError * error and NSError ** errorPointer. It’s not sufficient simply to declare the latter, and you definitely can’t use a construction such as &(&error), because &error basically just gives a number, which has no address itself. Finally, we have the method for creating the invocation:


-(NSInvocation *) invocationForDidSucceedAtTaskWithName:(NSString *)name {
	NSInvocation * invocation = nil;
	if (name) {
		SEL selector = NSSelectorFromString([NSString stringWithFormat:@"didSucceedAt%@:error:", name]);
		if (selector) {
			if (ivarInvocation) {
				invocation = [[ivarInvocation retain] autorelease];
				[invocation setSelector:selector];
			} else {
				NSMethodSignature * signature = [self methodSignatureForSelector:selector];
				if (signature) {
					invocation = [NSInvocation invocationWithMethodSignature:signature];
					if (invocation) {
						ivarInvocation = [invocation retain];
						[invocation setSelector:selector];
					}
				}
			}
		}
	}
	return invocation;
}
	

The invocation is stored as an instance variable because the method signature depends only on the argument and return types, so it will remain the same for all of our selectors. Now our apps can invoke errors at a rate matched only by analysts, economists, and pundits.

On a personal note, I’d like to invite my faithful readers (all three, including myself) to my wedding today. Although the location is unusual — the Virgin Megastore in Orange County — it will nonetheless be a traditional ceremony. Pamela Anderson is signing.

Selectors and performance anxiety

Sunday, March 25th, 2007

As I sit on my front porch looking at the 73° temperature (K, since I live on Neptune) in the weather widget on my new MacBook Pro, I can’t help but think that life is good. Yet there’s a nagging voice in the back of my head, reminding me of unresolved issues. Wait, that’s the cat wanting to come outside. In addition, I hear the echoes of Jim Kerr. Let’s forget about them, though, and talk about -[NSObject performSelector:withObject:afterDelay:]. This has absolutely nothing to do with my previous post, honest. You can trust me, because we Neptunians (Neptunites? Neptuners?) cannot lie. We’ve been known to exaggerate, but only once every billion years or so.

The question on all of our minds, at least those of us not suffering from March Madness (to be followed no doubt by April Antisociality and May Melancholy), is what happens when you call performSelector:withObject:afterDelay: with a delay of (NSTimeInterval)0.0 during application launch. It turns out that you can call this successfully pretty much anytime, even during -[NSApplication init], in which case the currentRunLoop will be created immediately rather than during -[NSApplication setServicesMenu:]. It’s also safe to call this as late as during the delegate method applicationDidFinishLaunching:. Regardless of when you call performSelector:, the selector will be performed during -[NSApplication nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:kCFRunLoopDefaultMode dequeue:YES] — not the first one, which returns an NSApplicationActivatedEventType, but the one after that. The second one returns an event of type NSFlagsChanged, but I’m not sure whether that matters.

If you call performSelector: multiple times during launch, the selectors will be performed consecutively, during the very same nextEventMatchingMask:, in the order in which they were set up to be performed. Everything seems to happen before any user events — keyboard, mouse, interface licking — are processed. Thus, my conclusion is that -[NSObject performSelector:withObject:afterDelay:0.0] is a safe and effective way of scheduling methods to be performed after application launch but before the user starts wrecking stuff and wreaking havoc. Of course, I also believed that beer was a safe and effective antiseptic, so take my conclusion with a grain of salt … just not in your wound.

Remember, Jim, ice cream is a dish best served cold.

Everything you always wanted to know about NSApplication

Saturday, March 10th, 2007

It seems that waiting for me to write a new blog post is like waiting for Larry David to write a new TV show. By the way, season one of Lap Cat Software Blog is available now on DVD for the low price of free ($35 shipping and handling). For those of you who don’t care for reruns, the wait is finally over: today is the season two premiere blog post! If you recall, in last season’s finale I was abducted by aliens and replaced by an evil clone. As we begin this season, I’m still the clone, but I’ve mellowed and become Lieutenant Governor. Confused?

I was confused about calling -[NSObject performSelector:withObject:afterDelay:] during application launch. Specifically, I was interested in a delay of (NSTimeInterval)0.0. When exactly, if ever, would the selector be performed? Is there a chance that user events could intervene? According to the documentation, The run loop for the current thread must already be running and in the default mode (NSDefaultRunLoopMode) for aSelector to be sent. For the purposes of investigation, I created an Xcode test project. In typical overkill fashion, I decided that getting to the bottom of the issue would require overriding every public method of NSApplication, NSMenu, NSRunLoop, NSThread, and NSWindow, along with some selected super and protocol methods. I threw in NSAutoreleasePool for good measure. In my main(), I put the following commands before the call to NSApplicationMain():

[[JJApplication class] poseAsClass:[NSApplication class]];
[[JJAutoreleasePool class] poseAsClass:[NSAutoreleasePool class]];
[[JJMenu class] poseAsClass:[NSMenu class]];
[[JJRunLoop class] poseAsClass:[NSRunLoop class]];
[[JJThread class] poseAsClass:[NSThread class]];
[[JJWindow class] poseAsClass:[NSWindow class]];

There was probably an easier way to do this, but I did what I did. I yam what I yam. You can download my project. As usual, it’s released under the SHAG license.

Leaving out many details, here is the basic sequence of events when you launch a Cocoa application. Your results may differ, so talk to your doctor before betting your life on this sequence.

  1. +[NSApplication sharedApplication].
  2. -[NSMenu initWithCoder:]
  3. -[NSWindow initWithContentRect:styleMask:backing:defer:]
  4. -[NSApplication setMainMenu:].
  5. -[NSApplication setWindowsMenu:].
  6. -[NSApplication setServicesMenu:].
  7. awakeFromNib.
  8. Enter -[NSApplication run]. This is the point of no return. That is, you never return from this method.
  9. Enter -[NSApplication finishLaunching].
  10. NSApplicationWillFinishLaunchingNotification.
  11. -[NSApplication makeWindowsPerform:@selector(_registerDragTypesIfNeeded) inOrder:NO].
  12. Return from -[NSApplication finishLaunching].
  13. Enter -[NSApplication nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:kCFRunLoopDefaultMode dequeue:YES].
  14. -[NSApplication activateIgnoringOtherApps:NO].
  15. NSApplicationDidFinishLaunchingNotification. Notice that the app already returned from finishLaunching a while ago (relatively speaking).
  16. -[NSApplication makeWindowsPerform:@selector(_visibleAndCanBecomeKey) inOrder:NO].
  17. Return NSEvent with type NSAppKitDefined, subtype NSApplicationActivatedEventType, from -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:].
  18. Enter -[NSApplication sendEvent:] with the same event.
  19. NSApplicationWillBecomeActiveNotification.
  20. NSApplicationDidBecomeActiveNotification.
  21. Return from -[NSApplication sendEvent:].

A few interesting notes:

  • NSThread. As you would expect, all of the application’s methods are called on the one, main thread. I’ve defined the macro JJTHREADLOGGING to verify this. For the main thread, which is returned by +[NSThread currentThread], none of the methods +[NSThread alloc], +[NSThread allocWithZone:], or -[NSThread init] are ever called.
  • NSAutoreleasePool. An autorelease pool is not created until after -[NSApplication finishLaunching] returns. If you call autorelease in your application delegate method applicationWillFinishLaunching:, an autorelease pool will not be created! Memory leak, anyone? The methods +[NSAutoreleasePool allocWithZone:] and -[NSAutoreleasePool init] are called many times, but they always return the same object, while -[NSAutoreleasePool release] and -[NSAutoreleasePool dealloc] are never called.
  • NSRunLoop. The run loop for the main thread is created in -[NSApplication setServicesMenu:]. Strangely, the run methods for the run loop ( -[NSRunLoop acceptInputForMode:beforeDate:], -[NSRunLoop limitDateForMode:], -[NSRunLoop run], -[NSRunLoop runMode:beforeDate:], -[NSRunLoop runUntilDate:] ) are never called.

If you’d like to try my project for yourself or modify it, I’d be very interested to hear about what you learn. I haven’t really investigated application termination, for example. You may have noticed that I also haven’t addressed how -[NSObject performSelector:withObject:afterDelay:] works during launch. I’m such a tease! These questions — and many others — will be answered in the next episode.

Solution: Fix the bug

Wednesday, January 3rd, 2007

I reported this bug well over a year ago, and I’m sure it was known before then.

Mac OS X: Exposé puts all open windows in one row

Issue or symptom

If you have several open windows that are lined up together and invoke Exposé, the windows will be shown in a single row (line) across the screen. For example, if the open windows are all touching the Mac OS X menu bar.

Products affected

  • Mac OS X 10.3 or later