Interesting questions are floating around about what changes iOS developers need to make, given the introduction of dual-core on the iPad 2, particularly in terms of threading. One question that came up is whether we should still default to nonatomic properties, as multiple threads could run through the getters and setters at the same time.

My opinion, at this time, and as expressed in a devforums thread, is that any code that will break under dual-core is already broken under single-core. The problem is not that two threads can execute simultaneously with dual-core, it’s that you have code sections that aren’t thread-safe and need to be. Dual-core will, at most, encounter the problem more frequently.

On iOS, we tend to make all properties involving UIKit nonatomic, meaning they do not synchronize access to the getter or setter (i.e., enforce a one-thread-at-a-time rule), for performance reasons. The reason for this really doesn’t have to do with the nature of atomicity, per se, it’s that any time you touch UIKit, you must do so from the main thread. Declaring nonatomic is just a consequence of this: the property should only be called from one thread, main, so you shouldn’t need to worry about coordinating multi-threaded access to the property. In other words, your thread management issues lie elsewhere, not with the atomicity of the property, so you can still declare these properties as nonatomic.

On the other hand, properties that aren’t related to UIKit may need to be atomic. If you think you’ll only ever call it from a single thread, fine, but if you’re not consciously enforcing that and just getting lucky, then you may be just one block, NSOperation, or callback on a mystery thread away from a nasty race condition.

In the first version of our iPhone SDK Development book, Bill and I all but ignored threading — NSOperation doesn’t even appear in the index — because we kept things simple enough that everything could be assumed to be running on the main thread. In the new world of blocks and Grand Central Dispatch, this is no longer a safe assumption, and we’d probably need to engage threading issues early. A greater awareness of threads and a willingness to use NSOperation or other threading approaches should help with performance on the new device too.

One thing I’m coming away from CodeMash with is a desire to clean up a lot of my old habits and dig into tools and techniques I’ve long known were available, but haven’t used. In some ways, I’m still stuck in my iPhone OS 2 ways in an iOS 4 world.

Daniel Steinberg has taken a pretty extreme position, but one that makes sense: he no longer has any private instance variables in his header files, since the current SDK allows you to put them in the implementation. Combined with the use of a class extension in the .m for helper methods, this makes it possible for the header to be exactly what it’s supposed to be: an exposure of the public interface to your class, with no clues about the implementation underneath.

To my mind, Daniel was also the winner of the “mobile smackdown” session, in which one presenter each from the iOS, Windows Phone 7, and Android camps was given 15 minutes to develop a trivial Twitter app that could manage a persistent list of user names and, when tapped, nagivate to that user’s twitter.com page. I say Daniel won because his iPhone app was the only one to complete all the features in time (actually, Daniel needed an extra 30 seconds to finish two lines of code). The Windows Phone presenter never made it to adding new names to the list, and the Android guy didn’t get around to showing the user’s page. One of Daniel’s wins was in using the “use Core Data for storage” checkbox: by graphically designing a data model for his “Twitterer” class, he picked up persistence and his table view in one fell swoop. Now that I think of it, I don’t remember how, or if, the other platforms persisted their user lists. I don’t use Core Data often, but after this demonstration, I’m much more inclined to do so.

There was a whole session on unit testing for iOS, something I just explored on my own for my first day tutorial (and even then, I was using it as much for illustrating the use of multiple targets in an Xcode project as for the actual testing of features). I’ve never been religious about testing, particularly given that GUIs have long proven difficult to make fully testable, but with a testing framework buit into Xcode (not everyone’s favorite, but it’s a start), it’s well worth rethinking how I could use it to get some measure of test coverage and fight regressions.

All of this makes me worry about the status of the iPhone SDK Development book I wrote with Bill Dudney. That was an iPhone OS 2 book that slipped far enough to be an early iPhone OS 3 book, with the addition of new chapters for important new frameworks like Core Data and Game Kit. But with iOS 5 surely looming, some of it is starting to look pretty crusty. In particular, the arrival of Grand Central Dispatch means that means that it’s no longer safe to blithely ignore threads, as we did, since there are scenarios where you can have even simple code that unwittingly manages to get off the main thread, which means trouble for UIKit. Furthermore, new frameworks demand blocks for completion handlers, so that’s something that now needs to appear early (and given that the block syntax is pure C, readers will need to be acclimated to C earlier than they used to). And I’ve long wanted to move the debugging and performance chapters (my favorites, actually) much earlier, so readers can figure out their own EXC_BAD_ACCESS problems. Not that I can currently even plan on a rev to that book – I still have four chapters to go on Core Audio, and would need a long and difficult conversation with the Prags besides. But I certainly see where my guidance to new developers has changed, significantly, in the last few years.

Betweeen Christmas break, a week of CodeMash prep and home office reorganization, and CodeMash itself, I feel like I’ve been off for a month (and my MYOB First Edge financial status would seem to agree). I feel ready to start anew this week, and making a clean break with the past suits this mood nicely.

Nothing major, I was just looking at some different approaches to setting contents of nib-loaded table cells that may need to be more dynamic than usual. I caught myself playing with key-value coding and thought that the following three lines – all of which do the same thing – were kind of neat:


cell.textLabel.textColor = [UIColor greenColor];
[cell.textLabel setValue: [UIColor greenColor] forKeyPath: @"textColor"];
[cell setValue: [UIColor greenColor] forKeyPath: @"textLabel.textColor"];

All you have to do to participate in KVC is to use properties, or follow a convention for naming getters and setters.

I’m looking at doing some custom tables (see my impromptu screencast on flippable cells) and was wondering about approaches to putting different kinds of cells different table instances. Seems like KVC would be one technique to get at the labels and other subviews of variant UITableViewCell subclasses, without having to know the actual class at compile time. Guess we’ll find out if it works nicely.

After last week’s crunch, closing the last of the errata and our own to-dos, we have officially sent iPhone SDK Development to production, meaning it will now get a second copy-edit, typesetting, printing, binding, and shipping to your anxious hands.

A note of thanks is in order to the beta-program purchasers and the thousands of errata they filed, along with over 500 forum discussions on the book. No getting anything past this group, that’s for sure.

Well, maybe one little thing. With the Snow Leopard release date now set, it looks like Apple engineers have a chance to reply to e-mail from several months ago. Last night, I heard back from the dns-sd.org folks (at an @apple.com address) about my request back in June to reserve a Bonjour service type for the Game Kit example in the book. The bad news is, I included an illegal character in my service name, so I had to change it from amiphd_p2p to amiphd-p2p, which is now part of the public list of DNS SRV (RFC 2782) Service Types. And the only reason that’s bad is that the book still has the name with the underscore, and I’m currently locked out of the book during production.

It’s a minor point, and it will get fixed, it’s just silly-bad timing, getting a reply to a two-month-old e-mail just a day after we wrapped the book.

Another interesting @apple.com e-mail has to do with the Clang Static Analyzer that we cover in the performance chapter, but that remains NDA for now. Anyways, they’ll have their own updates in due course, so watch their page.

Related point: I went to the Barnes & Noble on 28th Street for the first time in ages today, and drifted by the computer book section. It’s probably the biggest in Grand Rapids, for what that’s worth. Computer book sections are shrinking everywhere, particularly the programming sections, for a number of reasons: anything nichey is a non-starter at retail and is basically only available via Amazon and the like, programmers are eagerly jumping into eBooks (or bundles where you get a PDF now and the paper book when it’s ready), some programmers prefer the immediacy of blogs and other informal sources to stuffy books, and of course nearly any computer eBook of any significance is on bitTorrent (including ours, despite the fact that the unauthorized PDFs all clearly identify the reader who chose to post his or her copy). All of which goes to explain why your local retailer has less reason to stock computer books when they can make more money off political screeds and trifling fiction. And, as I discussed a few weeks back, why you’re going to continue to see fewer and fewer programming books going forward.

Still, the iPhone SDK is such a hot topic that even all this friction can’t stop it from being a popular topic with readers and authors alike. There were at least four other iPhone programming books on the shelves, and I took a first peek at several of them today. Note of explanation here: when writing a book, I never look at anything that could be considered a “competing” book. It’s my own mental firewall that ensures that my work is my own, and that I don’t lift ideas from fellow authors. That said, I do read the official docs, both to learn things myself and to make sure that the book I’m writing goes beyond what you can get for free. There’s no value for the reader (or the writer) if the book is just a paraphrase of Apple’s programming guides.

I think the only one on the shelves today that is officially updated for iPhone SDK 3.0 is Dave Mark’s Beginning iPhone 3 Development book, which features significant coverage of Core Data, probably the most significant of the new features in iPhone SDK 3.0. Of the older titles covering iPhone 2.x, I saw Erica Sadun’s, Jonathan Zdziarski’s, Neal Goldstein’s and Christopher Allen and Shannon Appelcline’s books.

They’re probably all worth a deeper read, though a glance through them and a mental comparison to my own project of the last year shows some similarities and differences. I’m sure all of us are grateful for the ease of getting screenshots from the simulator, as all the titles are rich with illustrations. Nearly all of them cover OpenGL, which ours actually doesn’t, I think because Bill thought that readers would be better served by studying OpenGL on its own (and that there isn’t enough unique about its iPhone implementation… as opposed to say, SQLite, which I put in the book not so much for the SQL or even the C API as for the strategies of managing the database files within an iPhone context: creating them with your Mac’s sqlite3 interactive shell, putting them in a bundle for deployment and backup, etc.). On the other hand, I think ours is the only book to talk about debugging and the various performance tools (Shark, Instruments, and the third-party Clang Static Analyzer). Unsurprisingly, given my inclinations, it looks like we hit media a lot harder than our peers. Counting the new-for-3.0 “Music Library Integration” chapter, we ended up with four media chapters, totaling nearly 75 pages. And that’s after cutting the too-hard-for-now Audio Streaming chapter.

It looks like all the other authors assumed a pre-requisite level equivalent to ours: know a curly-brace language, preferably C, and we’ll cover Objective-C as we go. We’ve had a few scripting-language converts (Flash/ActionScript people, it seems) on our forums who have a hill to climb with the latent subtle C-isms, mostly the memory stuff, and I wonder if our colleagues have had similar experiences with their audiences. C knowledge is a strange thing: all us old folks think it’s a lingua franca, yet I think we all know that younger developers no longer learn it as a matter of course, and may not be particularly eager to do so.

Anyways, I imagine everyone else is rushing out their 3.0 updates too, so it’ll be interesting to see what new features get covered, and what our readers still want from us in future versions or more advanced titles.

For reasons you don’t need to know about (yet), I wanted to get my usual crutch of a logging UITextview implemented in plain C.

I hadn’t wanted to mess with varargs, so I usually write an Obj-C method like this:


-(void) screenLog:(NSString*) s {
	textView.text = [NSString stringWithFormat:@"%@%@\n",
		textView.text, s];
}

What this does is to create an autoreleased NSString built from a format that’s just two strings concatenated together — the current contents of the text view and the argument string — and a new-line character. It then sets this new string as the new text of the UITextView

It sucks a little bit to call, because you have to pass in an NSString, not the usual varargs you’d use with NSLog. So to do:

NSLog (@"Current age: %d", 41);

you’d have to build the string up-front, like this:

[self screenLog: [NSString stringWithFormat: @"Current age: %d", 41]];

So, kind of annoying, but still useful when you want to log to the screen instead of standard out, like I’ve had to do this week while doing some Bonjour stuff between multiple devices scattered about the office, at most one of which gets to log to Xcode’s console. Yesterday’s post, with onscreen output of the two devices getting each other’s test message, shows why this is a nice crutch to have for experiments, prototypes, and throwaways.

Anyways, I actually wanted to do this with plain ol’ C, and happened across Matt Gallagher’s great write-up of varargs in Cocoa. Combining that with the realization that NSString has some method signatures that take a va_list, I was able to rewrite my screen logger in plain ol’ C:

void LogToUITextView (UITextView *view, NSString* format, ...) {
	va_list args;
	va_start (args, format);
	NSString* appendedText = [[NSString alloc]
				initWithFormat: format arguments: args];
	view.text = [NSString stringWithFormat:
				 @"%@%@\n", view.text, appendedText];
	[appendedText release];
}

Calling it feels a lot more like calling NSLog:

- (void)viewDidLoad {
    [super viewDidLoad];

	// customize point
	LogToUITextView(textView, @"Current age: %d", 41);
	LogToUITextView(textView, @"Current weight: %3.1f", 243.6);
	LogToUITextView(textView, @"Available fonts:\n %@",
				[UIFont familyNames]);
}

And check it out: it actually works:

varargs-logging-function

I’ll probably adapt the varargs approach in my Obj-C logging function going forwards, but still, it’s nice to be able to make the procedural C call, especially since you could switch all NSLog calls to LogToUITextView with a single global replace.

Update: Here’s an even “more C” version that’s functionally equivalent:

void LogToUITextView (UITextView *view, NSString* format, ...) {
	va_list args;
	va_start (args, format);
	CFStringRef appendedText = CFStringCreateWithFormatAndArguments (
		kCFAllocatorDefault,
		NULL,
		(CFStringRef) format,
		args);
	CFStringRef newText = CFStringCreateWithFormat (
		kCFAllocatorDefault,
		NULL,
		(CFStringRef) @"%@%@\n",
		view.text,
		appendedText);
	view.text = (NSString*) newText;
	CFRelease (newText);
	CFRelease (appendedText);
}

Obviously wordier, and we lose a convenient autorelease, since CoreFoundation doesn’t have autoreleasing.

You know things are going badly when you get errors so cryptic and so consistently that you write yourself a pretty-print method to make sense of them.

Here’s where I was as of last night:


- (void) failTo: (NSString*) functionName withOSStatus: (OSStatus) stat {
	NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain
			code:stat userInfo:nil];
	NSLog (@"Error in %@: %@", functionName, [error description]);
}

Which allows me to catch errors like this:


if (audioErr != noErr) {
	[self failTo: @"AudioQueueNewInput" withOSStatus: audioErr];
	return;
}

And which produces output like this. A lot.

2009-02-03 21:20:18.874 AQRecorderThrowaway[3522:20b] Error in AudioQueueNewInput: Error Domain=NSOSStatusErrorDomain Code=1718449215 "Operation could not be completed. (OSStatus error 1718449215.)"

And a little searching through the Audio Queue Services documentation tells us that 1718449215 is is the four char code for fmt?, also known as kAudioFormatUnsupportedDataFormatError.

Next Page »