Update September 12, 2012: I updated the article with some fixes for places where I was wrong, comments from Rob Napier and Mugunth Kumar, the two authors, and added a few more references. I apologize for the wrong statements I made. See the highlighted paragraphs below.
I really wanted to like this book. The market for books about iOS development is saturated with introductory books but titles that target the intermediate or advanced level are rare. I suppose this is understandable because beginners are the biggest market for programming books. So I was excited about iOS 5 Programming – Pushing the Limits (published in early 2012) by Rob Napier and Mugunth Kumar.
Despite my initial excitement, having read the book thoroughly, I cannot recommend it to anyone. You really should not buy it. It is difficult for me to advise so strongly against a book by two authors whom I greatly respect for their contributions to the developer community, be it their blogs, open-source components or tweets. Also, I know it’s so much easier to criticize the work of others than creating it so I hope Rob and Mugunth don’t take this review personal. I will still follow their writings, I just don’t think they have delivered their best work with this book. Let me explain.
My main reason for not recommending the book is the sheer number of factual errors. By that, I do not mean typos or small oversights but essential statements that can often be refuted by a look in the documentation. Or disputable opinions given as facts with no evidence at all. I will list most of the errors I have found at the bottom of this article.
Not as bad as blatant factual errors, but almost as important in my opinion, is the multitude of wrong or sloppy wording throughout the book. An experienced programmer can gloss over sentences where protocols are confounded with classes, classes with instances or drawing with compositing. In a book that targets intermediate developers who may not yet have internalized every term, mix-ups like these can leave the reader more confused than he was before. Again, refer to the bottom of this article for relevant examples.
To me, the errors I found are a sign of either serious sloppiness or lack of knowledge on part of the authors. I do realize that books about new technologies are regularly written under considerable time pressure and that it is nearly impossible to get every fact correct. In fact, nobody expects this. I my opinion, the mistakes in this book are more severe than usual and cannot just be explained with time constraints. The book could have benefited immensely from a thorough technical review.
Pushing the Limits?
My other criticism is about the level of the book and therefore much more subjective. In my opinion, only about one third of the contents really are about “pushing the limits” in that it deals with truly advanced topics. Some examples that I liked:
- A description of the
- An explanation of the notion of time in Core Animation animations.
- The discussion of
NSPurgeableDataand the differences between dirty and resident memory in Instruments’ VM Tracker.
- An explanation of run loops and blocking, read/write locks with concurrent queues and
- The very thorough chapter on Security with tutorials about verifying and trusting certificates, as well as symmetric encryption.
- The how-to on the inner workings of key-value coding and observing.
- The chapter on Core Foundation with a discussions on memory management, memory allocators, strings and collections. (Which pointed me to this wonderful Ridiculous Fish article on the origins of toll-free bridging.)
- The chapter on the Objective-C runtime.
On the other side of the spectrum are introductory chapters on Xcode and basic language features like naming conventions, categories and properties that should not waste space in an advanced book. Readers know this stuff already. If they don’t, they know they should read a beginner’s book first.
Sort of in between are topics that would warrant a deep discussion but are only mentioned briefly. At times, this reads like Apple’s What’s New in iOS 5 document. I got the feeling the authors felt they needed to mention new technologies like storyboards or appearance customization but did not want to expend too much time investigating them. The most glaring example of this is the section on iCloud. The meagre two pages the book devotes to this topic sound more like a marketing document from Apple about iCloud’s amazing capabilities than an informed discussion by people who actually used the APIs. Given the problems many developers had with implementing iCloud in their apps, it sounds even more ridiculous in hindsight. If you don’t have anything to add, better leave it out in the first place.
Reads Like a Recipes Book
Finally, some parts of the book read like a recipes book. For instance, rather than explaining how one can implement pull to refresh for a table view, the authors explain the usage of a third-party pull to refresh component, thereby spending little more than one page on the task, with no word on how the implementation works. Similarly, readers are advised to use a third-party networking library rather than learn about the intricacies of
NSURLConnection and how one would go about integrating it with an
NSOperationQueue. To me, this is exactly the wrong emphasis. And whatever it does, it doesn’t push the limits. I expected more from a book with this title.
Any criticism of the book’s level of difficulty and emphasis on certain topics is obviously debatable and I recognize that, being a somewhat experienced iOS developer, I may not be among the book’s target audience and therefore not the best judge of these aspects so take it as it is: an opinion. The factual errors I mentioned above are far more important.
List of Errors
The following is a list of most errors and inaccuracies I found in the book. It makes for some very dull reading but I feel I had to be thorough in my documentation. I hope it does not sound too nit-picky. The list is roughly in the order the issues appear in the book.
Throughout the book, selectors are often listed without the trailing colon (e.g.
Throughout the book, the authors speak of “category classes” when they mean Objective-C categories. Drives me crazy.
Talking about Build Schemes in Xcode:
You can duplicate the profile scheme so that you have two schemes: one launching Leaks and the other launching Time Profiler.
It would be great if Xcode schemes worked that way but unfortunately they don't. It's not possible to create custom or duplicate existing actions (such as Profile) in a scheme; the only thing you can do is duplicate the entire scheme with all its actions, which is overkill and hard to manage if all you want is edit a parameter for one of the several actions.
Suffix instance variables (ivars) with an underscore or prefix them with
The discussion of Automatic Reference Counting is confusing in places. The authors say multiple times that, under ARC, you should not call
Rob Napier: The lead-in paragraph isARC introduces four restrictions on your code…followed byNo calls toas one of the four restrictions. Is “restrictions” and “No” not explicit enough?
In the discussion of the singleton pattern,
Rob Napier: I really tried to explain the difference between real (I call them “strict”) and “shared” singletons on pp. 70-71. Is this not clear? Agreed that my pattern was out-dated, which is why I wrote the errata.
Upon re-reading this section, I have to agree with Rob. This is well described in this section and I did not read it carefully enough. I apologize for pointing this out as an error.
In most cases, nib files do not lower the performance compared to an equivalently coded UI.
If there is any evidence for cases where NIB files cause significantly lower performance than a UI created in code, the authors fail to mention it. The example they give compares a table cell composed in Interface Builder (with multiple subviews) to a performance-optimized table cell that does its own drawing, which I don't consider equivalent.
The sample code to manually load a NIB file uses
Update: Here's a relevant quote from the
Your application should use
once loaded, nibs are cached.
The authors provide no reference for this statement and I could not find any place where this is documented. My understanding is that the
An UINib object caches the contents of a nib file in memory, ready for unarchiving and instantiation. When your application needs to instantiate the contents of the nib file it can do so without having to load the data from the nib file first, improving performance.
The authors confound the terms “superclass” and “owning object”:
But a good design practice is to let the table cell handle the delegate and notify its super class.
The cell should notify its owner or delegate. It rarely makes sense for an instance to notify its superclass about an event.
The authors make no distinction between drawing and compositing systems. UIKit and Core Animation (mostly compositing systems, except for some drawing functionality in UIKit) are lumped together with Core Graphics under the term “drawing systems”. I doubt this makes the responsibilities of each framework any clearer to the reader. Later, Core Graphics is named as the
[UIKit] is the highest-level interface, and the only interface in Objective-C.
Wrong. Core Animation and Core Image also have object-oriented interfaces.
Sample drawing code steps down to the Core Graphics level to set
iOS does not perform partial view drawing, and
The documentation says the opposite. It's in the hand of the programmer whether the entire view will be redrawn or not. It's your responsibility to check the argument of
I tested this again and I can confirm that, on iOS 5.1.1, UIKit definitely passes the rectangle specified in
Again, UIKit is called the
[UIView] is a pretty heavyweight object, so you need to be careful about how many of them you use.
The authors don't offer evidence for this assumption. In my experiments with hundreds of views and layers, the memory overhead of views is negligible and the animation performance of views and layers is identical. From the standpoint of the graphics system, views and layers are identical.
The authors call
In the discussion of the
Update: I was wrong about this one. On iOS, the origin of Core Animation's coordinate system is in fact the upper left corner, with the y axis pointing downwards. Thanks to Nico Schmidt and Felix Gabel for pointing it out.
Sample code using ARC uses the
Because the parser uses delegation to return data, you need a subclass of NSXMLParser for every object you are handling.
On the contrary. Because it uses delegation, you don't have to subclass
Under the headline Parsing XML on iOS, the book discusses both XML SAX and DOM parsers. As an example of the latter, the authors talk briefly about
Internally, every web server is coded using some object-oriented programming language.
This claim is obviously wrong and also beside the point. The book is not about web server API design.
Something from the WTF? department in a discussion about designing model objects that should interface with web services:
When the reconstructed objects on your iOS app match 100 percent with the objects on the server, the goal of data exchange is attained and your app will be error free.
I never knew it was so easy to make my app error free.
The authors claim
When adding a delegate attribute to a singleton class, the authors chose the unconventional way of defining class methods
The sample code also does not specify the protocol the delegate should conform to in the method declaration (
A custom setter method for a retain-property is wrong. In it, the authors first
In the same context, the reader learns that he has to include KVO notifications (
This is very dangerous advice because the authors neglect to mention that the Caches directory is not guaranteed to remain intact. The OS is free to purge it at regular intervals or when storage space is limited. If an app puts data into the Caches directory that it cannot recreate, it will be irretrievably lost.
Apple modified the OS's cleaning behavior regarding the Caches directory in iOS 5. Given the book's timeframe, it was perhaps difficult to say anything concrete about the actual behavior of the OS, but the authors should definitely not have advised reader to put stuff into the Caches directory that is not meant for caching.
Rob Napier: Apple explicitly recommend putting files here you don't want backed up, and it wasn't clear during the betas that these files could be deleted (they weren't in iOS 4). This should have made the errata, however. It has been fixed in the iOS 6 book.
If you have information that you would rather the user not have access to, you can store it in the keychain or in
Again, this is a totally wrong way to use the Caches directory. If you don't want files to be readable in a device backup, use Apple's own Data Protection API, which seamlessly encrypts files on disk and has been available since iOS 4 (a topic the authors even discuss a few pages later).
Rob Napier: The Data Protection API does not apply if the user does not provide a PIN. So if the goal is to provide a little data hiding from casual investigation (which is the topic here), then Data Protection can't help. Given the pre-5.0GM behavior of not deleting these files, I believe this was reasonable advice when it was written. There are better ways now and the book has been updated.
In a code snippet, a view controller registers itself as a listener for a notification in the
The occasional plug for your own projects in your book is totally fine, especially if it is about stuff you're not making any money off. In fact, I'd expect it. I'd also expect that you disclose the fact that you are recommending your own stuff. In the chapter about in-app purchase, the authors recommend Mugunth Kumar's own MKStoreKit without mentioning this. The book devotes five pages to MKStoreKit alone and they sound like a commercial in places:
MKStoreKit … reduces [coding effort] to somewhere near zero. … With frameworks like MKStoreKit minimizing your coding efforts, why not give it a try?
Mugunth Kumar: We talk about ASIHTTPRequest, DTCoreText, EGOPullToRefreshView, SFHFKeychainUtils, SBJSON, JSONKit and a variety of selectively chosen third-party libraries as well. You can't push the limits if you write every component yourself. One should get rid of the “Not-invented-here” syndrome, choose the right third-party component and try to understand and use the library in their app. MKStoreKit has been used in a majority of games, including some from big-named publishers. Thirdly, I'm not selling MKStoreKit. There are no “commercial” intentions behind.
Sample code that uses key-value coding to send regular messages to objects:
While technically correct, this is horrible code! Please use a method like
Rob Napier: The goal here was to demonstrate higher order messaging in a simple example. I don't think enumerateObjectsUsingBlock: is the obvious solution … But that's not the point. The point was to demonstrate higher order messaging, which can be very powerful. For instance, the string above could be looked up dynamically, or even built dynamically, which allows operations that are can be difficult using blocks. It's not an everyday tool, but it is useful to know it exists.
I stand by my point that using KVC for other purposes than accessing attributes is a very bad practice. There are clearer ways to implement higher order messaging in Cocoa (blocks, invocations). Granted, these other solutions are not one-liners, but you don't need a one-liner for something you rarely use and can encapsulate nicely. A very good example of this concept (not using blocks) is given in Cocoa Design Patterns on pp. 321-326.
The authors implement a
Mugunth Kumar: True, but this was intentional. I wanted to focus on one thing. That one thing here is blocks. Talking about associative references + blocks + delegates means the chapter will lose its essence. Readers are not going to understand anything.
Any sqlite3 library … is almost always going to be slower than Core Data.
Again, a claim with no evidence. It goes on:
In addition, while sqlite3 is thread-safe, the binary bundled with iOS is not. So unless you ship a custom-built sqlite3 library (compiled with the thread-safe flag), it becomes your responsibility to ensure that data access to and from the sqlite3 database is thread-safe. Because Core Data has so much more to offer and is thread-safe, I suggest avoiding native SQLite as far as possible on iOS.
That sounds as if Core Data made multi-threaded access really easy. My experience is rather different.
Mugunth Kumar: A book is not a research publication where every claim needs evidence. In a chapter that doesn't talk about Core Data (this chapter talks about caching), I wouldn't prefer writing in depth about multi-threading with Core Data.
In a discussion about
For web views larger than 1024×1024, you need to break them up into smaller pieces and render them individually.
I am not entirely certain, but I believe this advice is no longer correct. Views had a maximum size of 1024×1024 in the early days of iOS but this limit is long gone. If I remember correctly, I just recently used
Core Text was originally designed on the Mac, and it performs all calculations in Mac coordinates. The origin is in the lower-left corner
Really, Mac coordinates? As if Core Graphics used different coordinate systems on iOS and Mac.
Rob Napier: I think “Mac coordinates” is a fair way to describe lower-left origin without confusing the reader.
The iOS 6 Edition
I regret the unfortunate timing of this review. The new edition of the book, updated for iOS 6, is not yet out but from what I’ve read, it’s probably too late in the production process to incorporate any of the changes I recommend here. The fact that the errata for the iOS 5 edition are currently very short makes me worry that most problems I identified have not been fixed in the new edition.
I’d love to be proven wrong.