You are previewing iOS 5 Programming Cookbook.

iOS 5 Programming Cookbook

Cover of iOS 5 Programming Cookbook by Vandad Nahavandipoor Published by O'Reilly Media, Inc.
  1. iOS 5 Programming Cookbook
    1. SPECIAL OFFER: Upgrade this ebook with O’Reilly
    2. A Note Regarding Supplemental Files
    3. Preface
      1. Audience
      2. Organization of This Book
      3. Additional Resources
      4. Conventions Used in This Book
      5. Using Code Examples
      6. We’d Like to Hear from You
      7. Safari® Books Online
      8. Acknowledgments
    4. 1. The Basics
      1. 1.0. Introduction
      2. 1.1. Creating a Simple iOS App in Xcode
      3. 1.2. Understanding Interface Builder
      4. 1.3. Compiling iOS Apps
      5. 1.4. Running iOS Apps on the Simulator
      6. 1.5. Running iOS Apps on iOS Devices
      7. 1.6. Packaging iOS Apps for Distribution
      8. 1.7. Declaring Variables in Objective-C
      9. 1.8. Allocating and Making Use of Strings
      10. 1.9. Comparing Values in Objective-C with an If Statement
      11. 1.10. Implementing Loops with For Statements
      12. 1.11. Implementing While Loops
      13. 1.12. Creating Custom Classes
      14. 1.13. Defining Functionality for Classes
      15. 1.14. Defining Two or More Methods with the Same Name
      16. 1.15. Allocating and Initializing Objects
      17. 1.16. Adding Properties to Classes
      18. 1.17. Moving From Manual Reference Counting to Automatic Reference Counting
      19. 1.18. Typecasting with Automatic Reference Counting
      20. 1.19. Delegating Tasks with Protocols
      21. 1.20. Determining Whether Instance or Class Methods Are Available
      22. 1.21. Determining Whether a Class Is Available at Runtime
      23. 1.22. Allocating and Making Use of Numbers
      24. 1.23. Allocating and Making Use of Arrays
      25. 1.24. Allocating and Making Use of Dictionaries
      26. 1.25. Allocating and Making Use of Sets
      27. 1.26. Creating Bundles
      28. 1.27. Loading Data From the Main Bundle
      29. 1.28. Loading Data From Other Bundles
      30. 1.29. Sending Notifications with NSNotificationCenter
      31. 1.30. Listening for Notifications Sent From NSNotificationCenter
    5. 2. Implementing Controllers and Views
      1. 2.0. Introduction
      2. 2.1. Displaying Alerts with UIAlertView
      3. 2.2. Creating and Using Switches with UISwitch
      4. 2.3. Picking Values with UIPickerView
      5. 2.4. Picking the Date and Time with UIDatePicker
      6. 2.5. Implementing Range Pickers with UISlider
      7. 2.6. Grouping Compact Options with UISegmentedControl
      8. 2.7. Presenting and Managing Views with UIViewController
      9. 2.8. Implementing Navigation with UINavigationController
      10. 2.9. Manipulating a Navigation Controller’s Array of View Controllers
      11. 2.10. Displaying an Image on a Navigation Bar
      12. 2.11. Adding Buttons to Navigation Bars Using UIBarButtonItem
      13. 2.12. Presenting Multiple View Controllers with UITabBarController
      14. 2.13. Displaying Static Text with UILabel
      15. 2.14. Accepting User Text Input with UITextField
      16. 2.15. Displaying Long Lines of Text with UITextView
      17. 2.16. Adding Buttons to the User Interface with UIButton
      18. 2.17. Displaying Images with UIImageView
      19. 2.18. Creating Scrollable Content with UIScrollView
      20. 2.19. Loading Web Pages with UIWebView
      21. 2.20. Presenting Master-Detail Views with UISplitViewController
      22. 2.21. Enabling Paging with UIPageViewController
      23. 2.22. Displaying Popovers with UIPopoverController
      24. 2.23. Displaying Progress with UIProgressView
      25. 2.24. Listening and Reacting to Keyboard Notifications
    6. 3. Constructing and Using Table Views
      1. 3.0. Introduction
      2. 3.1. Instantiating a Table View
      3. 3.2. Assigning a Delegate to a Table View
      4. 3.3. Populating a Table View with Data
      5. 3.4. Receiving and Handling Table View Events
      6. 3.5. Using Different Types of Accessories in a Table View Cell
      7. 3.6. Creating Custom Table View Cell Accessories
      8. 3.7. Displaying Hierarchical Data in Table Views
      9. 3.8. Enabling Swipe Deletion of Table View Cells
      10. 3.9. Constructing Headers and Footers in Table Views
      11. 3.10. Displaying Context Menus on Table Views Cells
      12. 3.11. Moving Cells and Sections in Table Views
      13. 3.12. Deleting Cells and Sections From Table Views
    7. 4. Storyboards
      1. 4.0. Introduction
      2. 4.1. Creating a Project with Storyboards
      3. 4.2. Adding a Navigation Controller to a Storyboard
      4. 4.3. Passing Data From One Screen to Another
      5. 4.4. Adding a Storyboard to an Existing Project
    8. 5. Concurrency
      1. 5.0. Introduction
      2. 5.1. Constructing Block Objects
      3. 5.2. Accessing Variables in Block Objects
      4. 5.3. Invoking Block Objects
      5. 5.4. Dispatching Tasks to Grand Central Dispatch
      6. 5.5. Performing UI-Related Tasks with GCD
      7. 5.6. Performing Non-UI Related Tasks Synchronously with GCD
      8. 5.7. Performing Non-UI Related Tasks Asynchronously with GCD
      9. 5.8. Performing Tasks After a Delay with GCD
      10. 5.9. Performing a Task Only Once with GCD
      11. 5.10. Grouping Tasks Together with GCD
      12. 5.11. Constructing Your Own Dispatch Queues with GCD
      13. 5.12. Running Tasks Synchronously with Operations
      14. 5.13. Running Tasks Asynchronously with Operations
      15. 5.14. Creating Dependency Between Operations
      16. 5.15. Creating Timers
      17. 5.16. Creating Concurrency with Threads
      18. 5.17. Invoking Background Methods
      19. 5.18. Exiting Threads and Timers
    9. 6. Core Location and Maps
      1. 6.0. Introduction
      2. 6.1. Creating a Map View
      3. 6.2. Handling the Events of a Map View
      4. 6.3. Pinpointing the Location of a Device
      5. 6.4. Displaying Pins on a Map View
      6. 6.5. Displaying Pins with Different Colors on a Map View
      7. 6.6. Displaying Custom Pins on a Map View
      8. 6.7. Converting Meaningful Addresses to Longitude and Latitude
      9. 6.8. Converting Longitude and Latitude to a Meaningful Address
    10. 7. Implementing Gesture Recognizers
      1. 7.0. Introduction
      2. 7.1. Detecting Swipe Gestures
      3. 7.2. Detecting Rotation Gestures
      4. 7.3. Detecting Panning and Dragging Gestures
      5. 7.4. Detecting Long Press Gestures
      6. 7.5. Detecting Tap Gestures
      7. 7.6. Detecting Pinch Gestures
    11. 8. Networking, JSON, XML, and Twitter
      1. 8.0. Introduction
      2. 8.1. Downloading Asynchronously with NSURLConnection
      3. 8.2. Handling Timeouts in Asynchronous Connections
      4. 8.3. Downloading Synchronously with NSURLConnection
      5. 8.4. Modifying a URL Request with NSMutableURLRequest
      6. 8.5. Sending HTTP GET Requests with NSURLConnection
      7. 8.6. Sending HTTP POST Requests with NSURLConnection
      8. 8.7. Sending HTTP DELETE Requests with NSURLConnection
      9. 8.8. Sending HTTP PUT Requests with NSURLConnection
      10. 8.9. Serializing Arrays and Dictionaries into JSON
      11. 8.10. Deserializing JSON into Arrays and Dictionaries
      12. 8.11. Integrating Twitter Functionality into Your Apps
      13. 8.12. Parsing XML with NSXMLParser
    12. 9. Audio and Video
      1. 9.0. Introduction
      2. 9.1. Playing Audio Files
      3. 9.2. Handling Interruptions While Playing Audio
      4. 9.3. Recording Audio
      5. 9.4. Handling Interruptions While Recording Audio
      6. 9.5. Playing Audio Over Other Active Sounds
      7. 9.6. Playing Video Files
      8. 9.7. Capturing Thumbnails From a Video File
      9. 9.8. Accessing the Music Library
    13. 10. Address Book
      1. 10.0. Introduction
      2. 10.1. Retrieving a Reference to an Address Book
      3. 10.2. Retrieving All the People in the Address Book
      4. 10.3. Retrieving Properties of Address Book Entries
      5. 10.4. Inserting a Person Entry into the Address Book
      6. 10.5. Inserting a Group Entry into the Address Book
      7. 10.6. Adding Persons to Groups
      8. 10.7. Searching the Address Book
      9. 10.8. Retrieving and Setting a Person’s Address Book Image
    14. 11. Camera and the Photo Library
      1. 11.0. Introduction
      2. 11.1. Detecting and Probing the Camera
      3. 11.2. Taking Photos with the Camera
      4. 11.3. Taking Videos with the Camera
      5. 11.4. Storing Photos in the Photo Library
      6. 11.5. Storing Videos in the Photo Library
      7. 11.6. Retrieving Photos and Videos From the Photo Library
      8. 11.7. Retrieving Assets From the Assets Library
      9. 11.8. Editing Videos on an iOS Device
    15. 12. Multitasking
      1. 12.0. Introduction
      2. 12.1. Detecting the Availability of Multitasking
      3. 12.2. Completing a Long-Running Task in the Background
      4. 12.3. Receiving Local Notifications in the Background
      5. 12.4. Playing Audio in the Background
      6. 12.5. Handling Location Changes in the Background
      7. 12.6. Saving and Loading the State of Multitasking iOS Apps
      8. 12.7. Handling Network Connections in the Background
      9. 12.8. Handling Notifications Delivered to a Waking App
      10. 12.9. Responding to Changes in App Settings
      11. 12.10. Opting Out of Multitasking
    16. 13. Core Data
      1. 13.0. Introduction
      2. 13.1. Creating a Core Data Model with Xcode
      3. 13.2. Generating Class Files for Core Data Entities
      4. 13.3. Creating and Saving Data Using Core Data
      5. 13.4. Reading Data From Core Data
      6. 13.5. Deleting Data From Core Data
      7. 13.6. Sorting Data in Core Data
      8. 13.7. Boosting Data Access in Table Views
      9. 13.8. Implementing Relationships in Core Data
    17. 14. Dates, Calendars, and Events
      1. 14.0. Introduction
      2. 14.1. Retrieving the List of Calendars
      3. 14.2. Adding Events to Calendars
      4. 14.3. Accessing the Contents of Calendars
      5. 14.4. Removing Events From Calendars
      6. 14.5. Adding Recurring Events to Calendars
      7. 14.6. Retrieving the Attendees of an Event
      8. 14.7. Adding Alarms to Calendars
      9. 14.8. Handling Event Changed Notifications
      10. 14.9. Presenting Event View Controllers
      11. 14.10. Presenting Event Edit View Controllers
    18. 15. Graphics and Animations
      1. 15.0. Introduction
      2. 15.1. Enumerating and Loading Fonts
      3. 15.2. Drawing Text
      4. 15.3. Constructing, Setting, and Using Colors
      5. 15.4. Drawing Images
      6. 15.5. Drawing Lines
      7. 15.6. Constructing Paths
      8. 15.7. Drawing Rectangles
      9. 15.8. Adding Shadows to Shapes
      10. 15.9. Drawing Gradients
      11. 15.10. Displacing Shapes Drawn on Graphic Contexts
      12. 15.11. Scaling Shapes Drawn on Graphic Contexts
      13. 15.12. Rotating Shapes Drawn on Graphic Contexts
      14. 15.13. Animating and Moving Views
      15. 15.14. Animating and Scaling Views
      16. 15.15. Animating and Rotating Views
    19. 16. Core Motion
      1. 16.0. Introduction
      2. 16.1. Detecting the Availability of an Accelerometer
      3. 16.2. Detecting the Availability of a Gyroscope
      4. 16.3. Retrieving Accelerometer Data
      5. 16.4. Detecting Shakes on an iOS Device
      6. 16.5. Retrieving Gyroscope Data
    20. 17. iCloud
      1. 17.0. Introduction
      2. 17.1. Setting Up Your App for iCloud
      3. 17.2. Storing and Synchronizing Dictionaries in iCloud
      4. 17.3. Creating and Managing Folders for Apps in iCloud
      5. 17.4. Searching for Files and Folders in iCloud
      6. 17.5. Storing User Documents in iCloud
      7. 17.6. Managing the State of Documents in iCloud
      8. 17.7. Handling Conflicts in iCloud Documents
    21. Index
    22. About the Author
    23. Colophon
    24. SPECIAL OFFER: Upgrade this ebook with O’Reilly
O'Reilly logo

1.17. Moving From Manual Reference Counting to Automatic Reference Counting

Problem

You want to learn about Automatic Reference Counting, Apple’s new Compiler solution to solving the headache that programmers had to deal with when working with objects and memory management in Objective-C.

Note

Automatic Reference Counting eliminates many of the manual reference counting issues that ultimately resulted in iOS apps that would crash here and there, and would be very unstable when deployed on user devices. ARC removes this headache by leaving most of the memory management complexity to the compiler.

Solution

Study the new storage attributes introduced with the latest LLVM compiler: strong, weak, and unsafe_unretained.

Discussion

In the latest LLVM complier, to use Automatic Reference Counting (ARC), we will need to deal with storage that is strong, weak, or unsafe and unretained. Any object under ARC is managed with one of these storage attributes. Here is a short explanation for each one:

strong

An object of this type is automatically retained at runtime and will be valid until the end of its scope, where it will automatically be released. For those familiar with Objective-C’s traditional way of memory management, this keyword is similar to the retain keyword.

weak

This is zeroing weak referencing. If a variable is defined with this keyword, when the object to which this variable points gets deallocated, this value will get set to nil. For instance, if you have a strong string property and a weak string property and set the weak property’s value to the strong property’s value, when the strong property gets deallocated, the weak property’s value will get set to nil.

unsafe_unretained

This is simply pointing one variable to another. This will not retain the object into the new variable, it will simply assign the object to the variable.

By default, all local variables are strong variables. In contrast, properties must explicitly specify their storage attribute. In other words, the compiler won’t assume that all properties without a storage attribute are by default strong properties. So do make sure that you specify the storage attributes for your properties. Let’s have a look at an example of the strong storage attribute. Let’s assume we have two properties called string1 and string2:

#import <UIKit/UIKit.h>

@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
           : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (nonatomic, strong) NSString *string1;
@property (nonatomic, strong) NSString *string2;

@end

Now if we initialize the string1 property with the string value of String 1 and assign this property’s value to the string2 property, we will see that with the strong storage attribute, the string2 property will keep its value even after string1 is deallocated:

#import "Moving_from_Manual_Reference_Counting_to_ARCAppDelegate.h"

@implementation Moving_from_Manual_Reference_Counting_to_ARCAppDelegate

@synthesize window = _window;
@synthesize string1;
@synthesize string2;

- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

  self.string1 = @"String 1";
  self.string2 = self.string1;
  self.string1 = nil;

  NSLog(@"String 2 = %@", self.string2);

  self.window = [[UIWindow alloc] initWithFrame:
                 [[UIScreen mainScreen] bounds]];

  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  return YES;
}

Note

Memory allocated for an object is disposed of when all strong variables pointing to that memory are deallocated.

Note

If you look closely at the implementation file, you will notice that the window property of our app delegate is synthesized on the _window instance variable of the class. This is how Xcode by default sets up our app delegate and we won’t be touching it in any of the examples in this book.

The output of this program is this:

String 2 = String 1

The strong, weak, and unsafe_unretained are most frequently used when declaring properties. You can take advantage of these storage specifiers even when declaring local variables, but you need to change the specifiers a bit. The strong specifier’s inline equivalent is __strong, weak specifier’s inline equivalent is __weak, and unsafe_unretained specifier’s inline equivalent is __unsafe_unretained. (Note that each of those keywords begins with two underline characters.) Here is an example:

- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

  /* All local variables are by default strong so just emphasis that. We
   really don't have to mention __strong for the first variable but
   to make it clear, we will set it. No harm in doing so. */
  __strong NSString *yourString = @"Your String";
  __weak   NSString *myString = yourString;
  yourString = nil;
  __unsafe_unretained NSString *theirString = myString;

  /* All pointers will be nil at this time */
  self.window = [[UIWindow alloc] initWithFrame:
                 [[UIScreen mainScreen] bounds]];

  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  return YES;
}

The unsafe_unretained storage specifier is truly unsafe, as its name implies. The reason for it being unsafe is if the object to which an unsafe_unretained variable points gets deallocated, this variable will not get set to nil and will point to a dangling location in the memory. Accessing this location might cause your application to crash. To avoid this, you should be using the zeroing weak referencing storage specifier, weak or its inline equivalent __weak.

Let’s see an example for zeroing weak referencing. Let’s change our string2 property’s storage specifier to weak instead of strong:

#import <UIKit/UIKit.h>

@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
           : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (nonatomic, strong) NSString *string1;
@property (nonatomic, weak) NSString *string2;

@end

When our app starts for the first time, we will initialize the strong string1 property and will assign string1 to string2. We will then set the value of the string1 property to nil. Then we will wait. This is absolutely crucial. If immediately after setting the value of string1 to nil, you print out the value of string2, chances are that you will get incorrect results instead of nil. So you need to make sure that your app’s run loop has gotten rid of all invalidated objects. In order to achieve this, we will print the value of strong2 when our app gets sent to the background. (This is caused by the user pressing the home button on their iOS device.) Once we’re running in the background, we know that the run loop has already gotten rid of invalidated objects in the memory and the results that we will get will be accurate:

/* 3 */
- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

  self.string1 = [[NSString alloc] initWithUTF8String:"String 1"];
  self.string2 = self.string1;
  self.string1 = nil;

  /* All pointers will be nil at this time */

  self.window = [[UIWindow alloc] initWithFrame:
                 [[UIScreen mainScreen] bounds]];

  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application{
  NSLog(@"String 2 = %@", self.string2);
}

Now run this app, wait a second or two, and press the Home button on the device/simulator. You will notice that the following results will get printed to the console window:

String 2 = (null)

This easily proved that the zeroing weak references work perfectly under ARC. Now to check how dangerous the unsafe_unretained storage specifier is, let’s go ahead and change the string2 property’s storage specifier to unsafe_unretained and repeat the exact same practice as we did for the weak property:

#import <UIKit/UIKit.h>

@interface Moving_from_Manual_Reference_Counting_to_ARCAppDelegate
           : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (nonatomic, strong) NSString *string1;
@property (nonatomic, unsafe_unretained) NSString *string2;

@end

Now if you leave the implementation of your app delegate as we had implemented it in the previous example (printing the value of string2 property when our app gets sent to the background), and you repeat the same procedure and open your app and send it to the background, you will crash! This means that when our app was sent to the background, we tried to print out the contents of an invalidated memory location that the string2 property was pointing to. Since the string2 property was unsafe and unretained, it didn’t know that the object that it was pointing to (in string1) was already deallocated when string1 was set to nil.

In addition to the aforementioned three storage specifiers, we can also use the __autoreleasing specifier. This storage specifier is most handy when we want to pass an object by reference to a method. This is required for when you want to call a method and leave that method responsible for allocating, initializing, and returning an instance of a class. The caller method will then have no responsibility at all to release the returned instance and will leave it to the runtime to decide when it is best to release the allocated instance of that class (handled by autorelease pools). For instance, if you have a method that needs to pass an error of type NSError to the caller method, the caller method will pass an uninitialized and unallocated instance of NSError to this method. This means the caller didn’t allocate memory for this error variable, so our method should do so. To do this, you must specify that this error parameter needs to be automatically released by the runtime when the right time comes:

- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError{

  NSArray *objects = [[NSArray alloc] initWithObjects:@"A simple error", nil];

  NSArray *keys =
  [[NSArray alloc] initWithObjects:NSLocalizedDescriptionKey, nil];

  NSDictionary *errorDictionary = [[NSDictionary alloc] initWithObjects:objects
                                                                forKeys:keys];

  *paramError = [[NSError alloc] initWithDomain:@"MyApp"
                                           code:1
                                       userInfo:errorDictionary];
}

- (BOOL)            application:(UIApplication *)application
  didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{

  NSError *error = nil;
  [self generateErrorInVariable:&error];

  NSLog(@"Error = %@", error);

  self.window = [[UIWindow alloc] initWithFrame:
                 [[UIScreen mainScreen] bounds]];

  self.window.backgroundColor = [UIColor whiteColor];
  [self.window makeKeyAndVisible];
  return YES;
}

In this example, the application:didFinishLaunchingWithOptions: method didn’t allocate the instance of NSError; the generateErrorInVariable method did. But for the compiler to understand the scope of the error object, the generateErrorInVariable method mentioned to the compiler that the object which will be created into its error parameter needs to be automatically released if it is no longer needed.

The best content for your career. Discover unlimited learning on demand for around $1/day.