First Edition Errata

Unfortunately mistakes happen especially in programming. Below is the list of known issues discovered in the published book.

Report New Errors/Findings/Issues

In General:

  • In some chapters (especially Chapter 2) of the digital version of the book the Command symbol (⌘) has been replaced with the letter "c". So if you see a shortcut key that looks like Option-c-4 know that it should be Option-⌘-4. (Update: The digital version has been correct and updates are available.)


  • No known issues at this time.

Chapter 1:

  • On Page 17, the Note section refers to the action name displayName:. It should read displayHelloName:.

Chapter 2:

  • No known issues at this time.

Chapter 3:

  • No known issues at this time.

Chapter 4:

  • On Page 83, ivars lastResult_ and headsCount_ should be _lastResult and _headsCount respectively.

Chapter 5:

  • On Page 95, in the Note section, "4-bit integer" and "8-bit integer" should be "4-byte integer" and "8-byte integer" respectively.

Chapter 6:

  • No known issues at this time.

Chapter 7:

  • No known issues at this time.

Chapter 8:

  • Figure 8.11 shows a toolbar at the top of the DetailViewController.xib. This is no longer correct with the latest version of Xcode. The Master Detail application template has changed. With the latest template generated code, there is no toolbar at the top of the DetailViewController NIB. Instead, the instance of DetailViewController created in the AppDelegate is added to a UINavigationController, which provides a navigation bar at the top.

Chapter 9:

  • Figure 9.4 shows the offending line of code that causes an uncaught exception. You may need to set a breakpoint for all exceptions to see the same line of code when running the sample code.
  • Listing 9.18 implements the UITableViewDataSource protocol method - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath. In the final release of Xcode 4.2 the fromIndexPath variable was renamed to sourceIndexPath and toIndexPath was renamed to destinationIndexPath.
  • In Listing 9.18, the implementation for tableView:moveRowAtIndexPath:toIndexPath: uses the exchangeObjectAtIndex:withObjectAtIndex: method found on NSMutableOrderSet. This is not correct. The implementation should have used moveObjectsAtIndexes:toIndex:. Here is the corrected implementation:
    - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
       NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:[fromIndexPath row]];
       [[self data] moveObjectsAtIndexes:indexSet toIndex:[toIndexPath row]];

Chapter 10:

  • On Page 237, DetailView should be DetailViewController. The second sentence in the first paragraph should read “The wheel view will be displayed in the DetailViewController.” Also, Step 1 that follows the first paragraph should read “Open DetailViewController.xib.”
  • At the bottom of Page 245, the file name DetailView.xib should be DetailViewController.xib.

Chapter 11:

  • In Listing 11.4, the logic used to calculate the angle of rotation can result in a divide by zero error. The problem is caused when the line 1 start and end are the same or when line 2 start and end are the same. A beautiful fix has been provided by Duncan C that not only solves the divide by zero problem, it simplifies the code. And it goes to show, math is hard.

Chapter 12:

  • On Page 281 at the end of the first full paragraph, the popover controller property name is called popoverController. This is incorrect. It should say masterPopoverController.
  • In Listing 12.7, the declared property popoverController references should be masterPopoverController.
  • If the image picker controller is displayed in a popover and you rotate the device, an exception is thrown with the reason “-[UIPopoverController dealloc] reached while popover is still visible.” This is caused by not dismissing the popover controller prior to setting the masterPopoverController property to a new reference or nil. Here is the updated code needed in DetailViewController.m:
    - (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
       barButtonItem.title = NSLocalizedString(@"Photo Albums", @"Photo albums title");
       [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
       [[self masterPopoverController] dismissPopoverAnimated:YES];
       self.masterPopoverController = popoverController;
    - (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
       // Called when the view is shown again in the split view, invalidating
       // the button and popover controller.
       [self.navigationItem setLeftBarButtonItem:nil animated:YES];
       [[self masterPopoverController] dismissPopoverAnimated:YES];
       self.masterPopoverController = nil;

Chapter 13:

  • In Listing 13.12 on Page 297, the line of code photoAlbum_ = photoAlbum should be _photoAlbum = photoAlbum
  • Figure 13.1 on Page 302 shows a screenshot of an earlier version of the PhotoWheel prototype project. The purpose of this screenshot is to show where you can find the list of linked frameworks. You may see a different list as you work through the book. For instance, QuartzCore.framework is listed in the figure image, but it is not needed by the PhotoWheel prototype app. Also, ignore the OneFingerRotatio…tureRecognizer.h and .m files shown in the Project navigator of the figure image. These were renamed to SpinGestureRecognizer.h and .m after the screenshot was taken.
  • On Page 304, the paragraph before Listing 13.14 includes the sentence “It also declares a utility method called save-Context that will save any outstanding changes in the managed object context.” The correct method name is -saveContext, not save-Context. Also, the code for -saveContext is missing from Listing 13.14 This is okay since the method is never used by the prototype app. If you want to see the code for -saveContext then create a new Xcode project that uses Core Data. The method will be included in the template generated code.
  • Figure 13.4 on Page 307 is a screenshot of the Core Data model editor. The screenshot was taken with the PhotoWheel project loaded. Ignore the project files shown in the Project navigator of the figure image. The PhotoWheel project is created in Chapter 14.
  • Step 5 on Page 308 introduces the flag “Allows External Storage.” It should be noted that to use this flag you must be running Xcode 4.2 or greater on Mac OS X 10.7 (Lion) or greater. If you are running Xcode 4.2 on Mac OS X 10.6 (Snow Leopard) then a number of errors are generated by the compile. For the purpose of learning, it is recommended you not set this flag if you are running Xcode 4.2 on Snow Leopard. While you would not storage large images in a Core Data persistent store in a production app, it’s perfectly okay to do it in the prototype app you build as you work through the book.
  • On Page 310, step 8 should read “Click the Add Relationship button (the one that earlier read Add Attribute).”
  • In Listing 13.21 on Page 317, the method declaration - (void)saveImage:(UIImage *)newImage has a trailing semicolon. This does not cause a compile error, but it is bad styling. It should be removed.
  • In Listing 13.21 on Page 317 in the saveImage: method, the line of code that initializes the local variable thumbnailImage has an extra bracket character at the end. The correct line of code is:
    UIImage *thumbnailImage = [self image:newImage scaleAndCropToMaxSize:thumbnailSize];
  • In Listing 13.31 on Page 324, the [tableView reloadRowsAtIndex:] call causes _UITableViewUpdateSupport to raise an assertion when there is one album name in the table view and the user taps it.. This crashes the app at runtime. The reloadRowsAtIndex: is used to force the previously and newly selected cells to set the accessory type. Another approach to this implementation is to set the accessory type explicitly within the implementation instead of relying on reloadRowsAtIndexPaths:. Here is the updated code (with the new lines of code highlighted):

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
       NSIndexPath *oldCurrentAlbumIndexPath = [NSIndexPath indexPathForRow:[self currentAlbumIndex] inSection:0];
       UITableViewCell *cell = [tableView cellForRowAtIndexPath:oldCurrentAlbumIndexPath];
       [cell setAccessoryType:UITableViewCellAccessoryNone];
       cell = [tableView cellForRowAtIndexPath:indexPath];
       [cell setAccessoryType:UITableViewCellAccessoryCheckmark];
       [self setCurrentAlbumIndex:[indexPath row]];
       PhotoAlbum *selectedAlbum = [[self data] objectAtIndex:[indexPath row]];
       [[self detailViewController] setPhotoAlbum:selectedAlbum];
  • On Page 325, the paragraph that starts with “As with the property list version, you need to add a property in DetailViewController called selectedWheelViewCellIndex” should also tell you to make the same changed made in Listing 13.9, which is to the highlighted list of code shown below:
    - (void)cellTapped:(UIGestureRecognizer *)recognizer
       [self setSelectedPhotoWheelViewCell:(PhotoWheelViewCell *)[recognizer view]];
       [self setSelectedWheelViewCellIndex:
        [[self data] indexOfObject:[self selectedPhotoWheelViewCell]]];
       BOOL hasCamera = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
       if (hasCamera) {
          [self presentPhotoPickerMenu];
       } else {
          [self presentPhotoLibrary];

Chapter 14:

  • On Page 346 under the Creating a Segue section, it says the Storyboard Segues HUD shows the performSegueWithIdentifier:sender: method. This is no longer true for the final release of Xcode 4.2. Instead the Storyboard Segues HUD looks like this:

    Lipad storyboardsegues hud

Chapter 15:

  • No known issues at this time.

Chapter 16:

  • The caption for Listing 16.19 refers to the file name PhotoWheelViewController.m. The correct file name is PhotoWheelViewCell.m.

Chapter 17:

  • In Item 22 on Page 466, the second sentence says, “in this custom getter method” when it should say “setter method.” The same is true in Item 23 on the same page. The sentence “This fires the custom setCurrentIndex getter method” should read “This fires the custom setCurrentIndex setter method.”

Chapter 18:

Chapter 19:

  • No known issues at this time.

Chapter 20:

  • In Listing 20.4 on Page 544, the second comment block should show the file name PhotoAlbumViewController.m, not .h.

Chapter 21:

  • In Listing 21.5, the class extension for ImageDownloader defines a declared property for the completion block. The property attribute strong should be copy. The correct line of code is:
    @property (nonatomic, copy) ImageDownloaderCompletionBlock completion;
  • Step 8 on Page 578 says “The method -disablesAutomaticKeyboardDismissal is an override method for NSViewController.” It should say the method is an override for UIViewController.

Chapter 22:

  • In Listing 22.1 on Page 594, the UIImage category method pw_imageScaleAndCropToMaxSize: is used. This category was from an earlier version of the PhotoWheel, and it never made its way into the book. Instead, the local method scaleAndCropToMaxSize: should be used. Also, the method -createScaledImagesForImage: should appear before the -saveImage: method to avoid having to create a forward declaration for -createScaledImagesForImage:. Here is the corrected source:
    - (void)createScaledImagesForImage:(UIImage *)originalImage
       // Save thumbnail
       CGSize thumbnailSize = CGSizeMake(75.0, 75.0);
       UIImage *thumbnailImage = [self image:originalImage scaleAndCropToMaxSize:thumbnailSize];
       NSData *thumbnailImageData = UIImageJPEGRepresentation(thumbnailImage, 0.8);
       [self setThumbnailImageData:thumbnailImageData];
       // Save small image
       CGSize smallSize = CGSizeMake(100.0, 100.0);
       UIImage *smallImage = [self image:originalImage scaleAndCropToMaxSize:smallSize];
       NSData *smallImageData = UIImageJPEGRepresentation(smallImage, 0.8);
       [self setSmallImageData:smallImageData];
       // Save large (screen-size) image
       CGRect screenBounds = [[UIScreen mainScreen] bounds];
       // Calculate size for retina displays
       CGFloat scale = [[UIScreen mainScreen] scale];
       CGFloat maxScreenSize = MAX(screenBounds.size.width, screenBounds.size.height) * scale;
       CGSize imageSize = [originalImage size];
       CGFloat maxImageSize = MAX(imageSize.width, imageSize.height) * scale;
       CGFloat maxSize = MIN(maxScreenSize, maxImageSize);
       UIImage *largeImage = [self image:originalImage scaleAspectToMaxSize:maxSize];
       NSData *largeImageData = UIImageJPEGRepresentation(largeImage, 0.8);
       [self setLargeImageData:largeImageData];
    - (void)saveImage:(UIImage *)newImage;
       NSData *originalImageData = UIImageJPEGRepresentation(newImage, 0.8);
       [self setOriginalImageData:originalImageData];
       [self createScaledImagesForImage:newImage];
  • On Page 603, the second paragraph says, “To listen for this notification, change the -managedObjectContext method in PhotoWheelAppDelegate.m to look like Listing 22.9.” The correct file name is AppDelegate.m.
  • On Page 606, NSFetchedResultsController is misspelled as NSFetchedResultController. The “s” is missing from “Results.”

Chapter 23:

  • In Listing 23.3 on Page 615, on final line of code, the ivar currentIndex_ should be _currentIndex to match the sample source code.

Chapter 24:

  • In Listing 24.12 on on Page 646, the ivar -filterButtons should be _filterButtons.

Chapter 25:

  • No known issues at this time.

Chapter 26:

  • On Page 684, the first paragraph mentions the "iPhone Developer Program." It is now called the iOS Developer Program.

Chapter 27:

  • No known issues at this time.

Appendix A:

  • No known issues at this time.