Build So Good

Continuing in my series of posts praising Xcode 41, I’d like to talk about the build confirmation sheet. This one:

If you press Command-B while Xcode 4 is already building, Xcode will bring down a sheet over the project window, saying “Stop build? A build action is already running”. There is also an option to not show the alert again.

Now, if I ever actually had to press that Stop button, this would not be a praise post. This would be the other thing. But in fact, under normal circumstances2, I never press that button. What happens instead is that Xcode chugs away on the current build, and then when that build is done, the sheet goes away, and a new build automatically starts.

This is so exactly what I want Xcode to do, it almost hurts.3

The sheets becomes a little UI reminder: Hey, you may have to wait a little longer for the build you just scheduled. And it’ll be easy to tell when it actually starts, because the sheet will animate away. I almost always want to wait for the build to finish anyway before doing anything else; I want to see whether the code I just wrote compiles without error and warning. So the sheet doesn’t impede me at all. It fits in with my workflow exactly.

And it’s been in Xcode 4 since the very beginning, as far as I remember.


1. If, on the other hand, you want to hear me complain about Xcode 4, follow me on Twitter. Or just read the second footnote. ↩︎
2. Under abnormal-but-still-frequent circumstances in Xcode 4.3, alas, the build never finishes, and I eventually have to force-quit Xcode to complete a build again. ↩︎
3. While it might seem logical to want a toggle, in practice, that’s not the case. Incremental builds never take long (if they don’t take forever, see above), so waiting isn’t hardship, and a toggle would always require two taps of Cmd-B, and having to be sure you get the timing right, or you’ll stop your own build. ↩︎

Xcode SDK Reminder

Even though Clark Cox hasn’t updated his blog in a while now1, he still has one post I don’t want to forget: “SDKs and Deployment Targets”, which walks through the Base SDK vs. Deployment Target Xcode settings. They can be confusing, but they’re vital to understanding how to build your app correctly.

Blogged it! Now I won’t forget.


1. And so in a bit of housecleaning, I’m unsubscribing. Sorry, Clark! ↩︎

Smells Funny

In “More on Apple’s Removal of Airfoil Speakers Touch From the App Store”, John Gruber of Daring Fireball has a detailed “back-and-forth with a few informed sources” about why Apple rejected the app.

The trouble? Per a tweet from Jeff Johnson, who works at Rogue Amoeba on Airfoil:

If Apple is talking to the press, it’s extremely underhanded and unethical, because they aren’t talking to us.

I don’t get a good feeling from this.

Pass It On

Update 5/23/2012: Mystery solved! See the end of this post below.

Until recently, for as long as I’ve been using Xcode, this code has never compiled successfully without warning:

#import <Foundation/Foundation.h>

@interface Foo : NSObject
@end

@implementation Foo

– (void)myMethod {
[self myPrivateMethod];
}

– (void)myPrivateMethod {}

@end

Can you see why? The method myPrivateMethod is never declared, and it isn’t defined until after its first usage in myMethod. Since C compilers are, as far as I’m aware, by standard implementation if not formal definition single-pass compilers, that first usage should have been flagged as something the compiler didn’t know about.

In Xcode 4.3.2, the current version of Xcode, the compiler doesn’t make a peep.

This is big.

Many of all the ancient, crufty things we hate about C and C-derived languages are due to that single-pass compilation — predeclarations and declarations of methods and classes (and everything), #import and #include statements, .h files at all. Java, for example, has none of these things.

What if clang got rid of all of that for Objective-C?1

John Siracusa in his 2011 episode of Hypercritical “A Dark Age of Objective-C” bemoaned how Apple was dragging its feet about moving on from its current legacy language and runtime to something more modern and competitive.

What if they’ve already started, without telling anyone?2

Update 5/23/2012: Turns out, it’s not a conspiracy, it’s a bugfix.3 Discussed in this March 6, 2012 thread in the Xcode-users mailing list. The thread points to this llvm commit on August 31, 2011 and mentions that the behavior is new to Xcode 4.3. It also mentions this post on the Apple DevForums, but I get an error when I try to go to it. (I really wish Apple made its non-NDAed DevForums posts freely available on the web.)

Thanks to Andy Lee for the information.

So I guess clang isn’t taking over the world, just yet? It’s too bad…


1. C functions still require declaration before usage. ↩︎
2. As with the recent improvements to the Core Data modeling tools, this is a mysteriously unheralded improvement. I couldn’t find any mention of it in (an admittedly brief perusal of) either Xcode or clang release notes. ↩︎
3. Which would be a pretty good name for a podcast episode. ↩︎

Upgrading to the Next Model

Xcode’s new Core Data model file format, introduced with Xcode 4.1 in 2011, never made any waves in Cocoa development blogs that I saw.1 Which is a shame, because it’s a pretty kick-ass improvement. Instead of a binary plist format (more specifically, Cocoa objects serialized directly to disk in a binary plist format), it’s eminently readable and diffable XML.

It reminds me, for two reasons, of Mark Pilgrim’s complaint about Apple’s switch from the standard .mbox format to the (Spotlight-friendly, but undocumented) .emlx format in Mail.app in Mac OS X 10.4, which was part of his rationale (last straw?) for leaving the Mac ecosystem and moving to Linux. (See this Daring Fireball article about it, since Pilgrim’s blog posts are now only available via the Wayback Machine.)

For one, it’s because my experience with the new format involved what I remember to be an involuntary switch. The details are a little fuzzy for me now (a good reason to write these blog posts in a more timely manner), but I recall my edits being saved in the new format without my having done anything to warrant it, and without any prompting on Xcode’s part. Just like Mark’s experience in Mail. If Xcode did make a habit of that, I would be rather annoyed, and for the same reason. (As an aside, I go on about this at some length in my first podcast (link forthcoming2 due to this mistaken remembrance. See the second podcast for followup, or just read the rest of this post.) I’m a sophisticated enough user that I care about format switches, mostly for the sake of backwards compatibility. For non-technical users, losing that compatibility might be fine. Developers, however, are by their nature not non-technical users.

It turns out, I can’t reproduce that experience now with fresh reinstalls of Xcode 4.0.2, 4.1, and the latest Xcode 4.3.2. Instead, the only thing that changes the format is for you to explicitly change it in the model’s inspector pane. Which is great. Exposing that level of control over a file’s format is exactly what a developer tool should do. And they do it for other important file types too, like xibs. So, kudos.

For two, it’s because this is kind of Mark’s experience in reverse. Going from a less standard format to a more standard format. (I did say “kind of”.) While it isn’t documented, it is uncluttered, as far as I can tell, by the kind of unreadable binary garbage that pollutes other XML file formats. Entities are referred to solely by name, not UUID. Attribute titles are simple and understandable. From a practical perspective, this will make the SCM diffs you do every day far more useful and enjoyable. But I could also see someone using a script to mechanically put together a Core Data model file, much more easily than you would put together an Xcode project file. And going further, I could see someone writing a third-party Core Data modeling tool that spits out one of these. I’m almost surprised someone hasn’t done it already, though the Xcode 4 Core Data modeling tool is good enough (and free) that there probably isn’t much demand for it.


1. Is it because everyone used the Xcode betas but couldn’t talk about them, so by the time Xcode was publicly released, it was old news? I also remember thinking that there weren’t that many people talking about Xcode 4 on its release, despite it being a vast change. ↩︎
2. Yes, there’s going to be a podcast soon. I’m collaborating with Wolf Rentzsch on it. Patience. (I.e. I won’t answer questions about it just yet.) ↩︎

Bigger

On recent Build and Analyze and Hypercritical podcasts, Marco Arment and John Siracusa, respectively, talked about the rumors of a bigger iPhone screen.

John predicted that Apple would only make the screen a little taller, but Marco observed that any resolution change would mean significantly more work for developers.

My take is the latter rules out the former: Apple won’t and can’t make a little change. Anything that requires new developer work opens the possibility that many/most developers won’t do it promptly or at all, making Apple look bad. The Cudgel of Rejection only works for new apps; for old apps, there has to be a carrot that motivates developers to rush out new versions with support for the new resolution.

And while I don’t know what it will be (I can’t even hazard a guess), I believe it won’t be a minor hardware upgrade.

Economies of Scalar

I came across something peculiar in a coworker’s custom Core Data entity class recently: boilerplate code for getter/setter methods that looked like it had been generated by Xcode, but was based on scalar rather than object values, like so:

- (NSInteger)age;

- (NSInteger)age {
    [self willAccessValueForKey:@"age"];
    NSNumber *result = [self primitiveAge];
    [self didAccessValueForKey:@"age"];
    return [result integerValue];
}

He swears this boilerplate code is untouched Xcode-generated code, but every Xcode I tried only generated object-based code. (Spoiler: he doesn’t remember, but I think he must have written it himself, like Apple recommends.)

Xcode doesn’t even generate object-based boilerplate anymore by default. As of 10.5 and up, the runtime will create object-based getter/setter methods for you, so Xcode only generates property stubs, like this:

@property (nonatomic, retain) NSNumber *age;

@dynamic age;

Very nice, but Xcode 4.2 has a curious new checkbox called “Use scalar properties” in the class generation sheet:

Screenshot of a portion of Xcode's Create NSManagedObject Subclass sheet, with the 'Use scalar properties for primitive data types' checkbox highlighted

When you check it, the new property declaration/definition is indeed scalar-based:

@property (nonatomic, retain) uint16_t age;

@dynamic age;

Could I use this to replace the mysterious boilerplate in my coworker’s class? Well….

If you build and run this, it’ll work just fine sometimes. But some people have reported problems with it. (Can’t find the link right now, sorry.) The trick is that this new ability to generate scalar-based getter/setters at runtime is limited to iOS 5 and Mac OS X 10.7 “Lion”, and won’t work on earlier versions of those OSes. (To make matters worse, Apple’s documentation hasn’t been updated to mention this scalar functionality at all.)

Hm…I want the benefits of runtime-created getter/setters, which will almost certainly be more efficient than manually boxing and unboxing NSNumber objects in my own code…but I also want to support the older OSes. What’s a programmer to do?

mogenerator to the rescue!

mogenerator is…well, I’ll just put in the “elevator pitch” from the website:

mogenerator is a command-line tool that, given an .xcdatamodel file, will generate two classes per entity. The first class, _MyEntity, is intended solely for machine consumption and will be continuously overwritten to stay in sync with your data model. The second class, MyEntity, subclasses _MyEntity, won’t ever be overwritten and is a great place to put your custom logic.

mogenerator’s default template declares object-based getter/setters and also declares a second set of fully-implemented scalar-based getter/setters. For example, if the object-based accessor is age, then the the scalar-based getter is ageValue.

But I want something a little different: I want a scalar-based definition of age and setAge:, but only if the OS is earlier than 5.0/10.7. If not, I want no definition, so that the OS will generate it for me.

How do I do that? Here’s a partial example of a mogenerator-generated “machine” entity source code file, using my custom template:

#import <objc/runtime.h>

#import "OSVersion.h"

@implementation _Measurements

@dynamic age;

static short ageIMP(id self, SEL _cmd) {
    [self willAccessValueForKey:@"age"];
    NSNumber *result = [self primitiveAge];
    [self didAccessValueForKey:@"age"];
    return [result shortValue];
}

+ (BOOL)resolveInstanceMethod:(SEL)selector {
    if ([OSVersion isLionOrGreater] == NO) {
        if (selector == @selector(age)) {
            class_addMethod([self class], selector, (IMP)ageIMP, 
                [[NSString stringWithFormat:@"%s@:", @encode(short)] UTF8String]);
            return YES;
    }

    return [super resolveInstanceMethod:selector];
}

There are two tricks here. First is the use of resolveInstanceMethod: to add the method implementation, stashed in the otherwise hidden ageIMP() function. The code here is straight out of Apple’s documentation, so take a look there for details.

Second is the use of the custom class OSVersion, which conveniently tells us which OS version we’re running on. That class is included in my mogenerator-Sample project on github (my first!).

Note: my github project’s sample app uses scalar getter/setters via a rather impractical UI, because for simple projects, object-based methods really fit better with Cocoa design patterns. For example, an object must be used as the value of an NSTableView cell. It’s only when you have more custom UI (or none) that scalar methods start making sense.

The most important detail, however, is that isLionOrGreater must be fast, because it is called dozens of times for even one simple class. In my first implementation, which wasn’t fast, I managed to slow down our iPad app by about 30 seconds (!).

The Serving of the Snark

I’ve enjoyed all the recent tweets from the Mac intelligentsia as they try out various phrases with Siri on an iPhone 4S, and report back the often whimsical results. “Open the pod bay doors” is of course a classic, as well as “Beam me up” and “What’s the meaning of life”.

I think the sheer variety we’re seeing, and the, let’s call it the level of teasing, is directly based on how all the content comes from Apple’s servers, not the local copy of iOS on your phone. And that’s for three reasons.

1. Space. As we’ve seen, there are often multiple responses for each phrase. And there are different responses if you’ve repeated a phrase versus saying it new. While each response might only take up a tiny amount of space, 5-10 answers for every single thing Apple engineers think of responding to probably adds up.

2. Schedule. I would bet real money that at least some of the answers that have so tickled the Mac/iPhone tech folks were invented after iOS 5 went golden master, after all the exhaustive testing that was done to ensure that it worked well enough to ship. There just wouldn’t have been time to both finish the feature and add this level of polish for a 1.0 release.

3. Response time. This one’s the killer. I think the reason Apple can provide the cutesy answers that it does is in part because they know they can yank any particular answer in a heartbeat. Otherwise, if they came up with a snarky response that offended someone, that made the news and gave them lots of bad press, the earliest they’d be able to fix it on the device itself might be months away, given other iOS priorities and testing requirements. Apple has a large and busy contingent of lawyers, and I think they would have limited the OS itself to a much more conservative set of responses if they knew they might be stuck with them for a long, long time.

Instead, the Apple engineers must be feeling an unfamiliar sense of freedom. They can provide jokes to statements like “I need to hide a body” and “Talk dirty to me” and “Who’s your daddy”. I’m sure, at some point, we’ll find one that’s in bad enough taste that it’ll make the news.

But we won’t find it for long.

Note #1: I’ve thought a lot about Matt Gemmell’s “SEO for Non-Dicks” article, but I can’t bring myself to switch from whimsical titles to titles “that are relevant to the content”. It’s always going to be a pun or a reference or something. If it keeps me from getting hits, well, I can live with that. Good advice if you’re smarter than me, though.

Note #2: Since I’m talking about snark anyway, I’m going to throw in a plug for Dan Benjamin for his role as co-host on many of the 5 by 5 podcasts. Mostly he’s there to listen and goose things along a bit, but I find that his understated, deadpan snark makes the episodes a lot more enjoyable. The reaction of his co-hosts to the little digs he makes is classic. John Gruber plays along with even drier wit, while both Marco Arment and John Siracusa just kind of pause in annoyance before continuing. It amuses me, anyway.

Legacy

1. “Bottom Feeding”

Many of my colleagues in the Mac/iPhone/iPad developer community had a deep, personal connection to Steve Jobs, which they expressed on Twitter and in blogs immediately after his death. I’ve never seen anything like it, and I’m grateful for it.

Along the way, I saw a number of attacks on those who didn’t stick to the positive: Daniel Jalkut called it “bottom feeding”, and Jeff LaMarche called it “cruel”, “hurtful”, and “little”.

Personally? The unwavering praise combined with a circling of the wagons made me uncomfortable, and awoke my contrarian nature.

Do you think the man who started phone calls with strangers by swearing at them would begrudge a realistic portrayal of himself after death? Articles on public figures, including obituaries, don’t omit flaws and failures. The page-long article from the October 8th issue of The Economist called “The Magician”, for example, has, amid the tribute, a single-sentence caveat in it.

We haven’t had our caveat yet.

2. “Mourning a Billionaire”

Here’s a tweet from Jana Olsen on October 6th: “Kind of weird how we all went from talking about a huge protest against big business to mourning a billionaire.”

The Occupy Wall Street movement started its encampment in New York City on September 17, over two weeks before Steve Jobs died. His death prompted criticism of the group from both the right and the left. The right made fun of the protesters for the contradiction of protesting the actions of the richest 1% while grieving the death of a very rich one. The left hectored the protestors for feeling any sympathy for Jobs at all.

I’m a lifelong Mac developer. I’m also as liberal as they come, and it’s becoming harder and harder to reconcile the two. On the one hand: the Apple vision of ever-sleeker, ever more useful devices connected to a burgeoning global network of information. On the other: the end of the Western way of life when the oil dries up with no realistic substitute. On the one hand: a thriving consumer market and developer ecosystem providing a good standard of living for many of my colleagues and friends. On the other: deepening unemployment and inequality, fostered by a corrupt media and political class.

3. “Steve Jobs Didn’t”

The always insightful Horace Dediu wrote a clever article using the deflation of some of the myths attributed to Steve Jobs to point out his true accomplishments.

I’m going to be less original, and point out the things that he really didn’t do:

1. He didn’t challenge the entrenched, monopolistic power of most of the industries Apple got involved with. While the big music labels are dying, that’s not Apple’s doing, and in some ways Apple helped prop them up temporarily by dragging them into the digital age. Apple has done nothing to disrupt the movie/television/cable industry that’s in the process of killing TiVo and Netflix. And the telephone carriers, while they can’t dictate phone models like they used to, still follow anti-consumer practices with impunity.

2. He didn’t break the glass ceiling or the tech industry boy’s club. The current Apple executive bios page contains no women. The parts of Apple that I saw had the same lopsided ratios of men to women in their engineering sections as the rest of the industry. I’m not without blame: when I was a hiring manager at Apple, I didn’t try hard enough to find qualified women candidates, and I’m sorry for that.

3. He didn’t help prepare the industry for the post-peak oil era. Bit more of a futuristic point than the others, and even more crazy-hard, but still true.

4. Perhaps most importantly in the near term, he didn’t challenge two great harmful industrial trends, the outsourcing that has all but destroyed America’s manufacturing base and jobs, and the employment of foreign companies that cut corners and endanger workers in order to keep prices low.

You can argue that none of these things were his responsibility, that he had his own company to run and his own vision to follow (which he did extremely well). You can argue that these problems are simply insurmountable or just the Way Things Are—many do.

The reason I think it’s worthwhile to bring these things up in the context of Steve Jobs, in the context of our Mac community, at this very moment, is that our praise of Steve Jobs brings it all to a head: if he was so innovative and unorthodox and uncompromising, if he could achieve the impossible (if he was, as the Onion snarked, the “last American who knew the fuck what he was doing“), what does that say about how we view these problems when we give him a pass on them? They’re worse than impossible? They’re not anyone’s responsibility?

Or as a beginning, maybe this, trite as it is: there’s a lot of bad shit coming down the pike, and we can’t rely on our heroes to save us from it.

Cocoa Swap

A fair number of my colleagues at Apple wouldn’t touch C++ with a ten-foot pole1. Which is a shame, because it has some good ideas.

One idea that’s stuck with me in the 8 years (8 years!) since I wrote my first draft of this post is std::swap().

You use std::swap() like so: instead of doing all your work on your actual objects, you do it on temporary objects instead. Reading in a file’s contents, making a change to your document, parsing a user’s input, it all happens detached from your data model. When the work, and all the possibilities for errors, have been slogged through, you use std::swap() to exchange the temporary objects’ content with that of the real objects.

This is important in C++ because codeflow-interrupting exceptions are a much larger part of error-handling, and because std::swap() is guaranteed not to throw.

Why should I care about this in Objective-C? After all, Apple’s developer documentation goes out of its way to discourage any use of exceptions for normal error handling, instead recommending that methods use NSError parameters2.

Let’s leave aside that it can be rather cumbersome to add an extra parameter to all of your methods, and to be sure deeply nested errors are passed all the way up. Even if no exceptions are thrown, if you encounter an error in the midst of complex changes to your data model, it can be tough to back all the changes out safely. Using temporaries reduces that risk to zero.

Is it worth it? You may, after all, wind up swapping out your entire data model if the changes you’re accumulating are extensive. If you’re working on a 4 GB image file, for example, then this technique probably isn’t for you.

And what if one of the things you’re changing is a file? Here, too, you can swap a temporary with the real thing in a way that’s virtually guaranteed never to cause problems—at least, if you’re willing to drop down a bit from the high-level Cocoa APIs and use Core Service’s FSExchangeObjects() method. (And are willing to bet that a method that uses FSRef types isn’t going to be deprecated. Hey, they ported it to iOS.) My understanding is that FSExchangeObjects() makes only HFS+ metadata changes, if the two files are on the same HFS+ partition. No worries about running out of disk space, permissions, etc. You can use it for ten files in a row, and they should all Just Work.


1. A fair number of my other colleagues at Apple were C++ fiends. ↩︎
2. “Instead of exceptions, error objects (NSError) and the Cocoa error-delivery mechanism are the recommended way to communicate expected errors in Cocoa applications.” ↩︎