Beginning ARC in iOS 5 Tutorial Part 1

Update 10/24/12: If you’d like a new version of this tutorial fully updated for iOS 6 and Xcode 4.5, check out iOS 5 by Tutorials Second Edition! Note from Ray: This is the twelfth iOS 5 tutorial in the iOS 5 Feast! This tutorial is a free preview chapter from our new book iOS 5 […] By Ray Wenderlich.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 6 of this article. Click here to view the first page.

The App

To illustrate how to use Automatic Reference Counting in practice, I have prepared a simple app that we are going to convert from manual memory management to ARC. The app, Artists, consists of a single screen with a table view and a search bar. When you type something into the search bar, the app employs the MusicBrainz API to search for musicians with matching names.

The app looks like this:

descr

In their own words, MusicBrainz is “an open music encyclopedia that collects, and makes available to the public, music metadata”. They have a free XML web service that you can use from your own apps. To learn more about MusicBrainz, check out their website at http://musicbrainz.org.

Go ahead and download the starter project for this tutorial and open it in Xcode. The project contains the following source files:

  • AppDelegate.h/.m: The application delegate. Nothing special here, every app has one. It loads the view controller and puts it into the window.
  • MainViewController.h/.m/.xib: The view controller for the app. It has a table view and a search bar, and does most of the work.
  • SoundEffect.h/.m: A simple class for playing sound effects. The app will make a little beep when the MusicBrainz search is completed.
  • main.m: The entry point for the app.

In addition, the app uses two third-party libraries. Your apps probably use a few external components of their own and it’s good to learn how to make these libraries play nice with ARC.

  • AFHTTPRequestOperation.h/.m: Part of the AFNetworking library that makes it easy to perform requests to web services. I did not include the full library because we only need this one class. You can find the complete package at: https://github.com/gowalla/AFNetworking
  • SVProgresHUD.h/.m/.bundle: A progress indicator that we will display on the screen while the search is taking place. You may not have seen .bundle files before. This is a special type of folder that contains the image files that are used by SVProgressHUD. To view these images, right-click the .bundle file in Finder and choose the Show Package Contents menu option. For more info about this component, see: https://github.com/samvermette/SVProgressHUD

Let’s quickly go through the code for the view controller so you have a decent idea of how the app works. MainViewController is a subclass of UIViewController. Its nib file contains a UITableView object and a UISearchBar object:

descr

The table view displays the contents of the searchResults array. Initially this pointer is nil. When the user performs a search, we fill up the array with the response from the MusicBrainz server. If there were no search results, the array is empty (but not nil) and the table says: “(Nothing found)”. This all takes place in the usual UITableViewDataSource methods: numberOfRowsInSection and cellForRowAtIndexPath.

The actual search is initiated from the searchBarSearchButtonClicked method, which is part of the UISearchBarDelegate protocol.

- (void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar
{
	[SVProgressHUD showInView:self.view status:nil 
      networkIndicator:YES posY:-1 
      maskType:SVProgressHUDMaskTypeGradient];

First, we create a new HUD and show it on top of the table view and search bar, blocking any user input until the network request is done:

descr

Then we create the URL for the HTTP request. We use the MusicBrainz API to search for artists.

NSString *urlString = [NSString stringWithFormat:
  @"http://musicbrainz.org/ws/2/artist?query=artist:%@&limit=20", 
  [self escape:searchBar.text]];
NSMutableURLRequest *request = [NSMutableURLRequest 
  requestWithURL:[NSURL URLWithString:urlString]];

The search text is URL-encoded using the escape: method to ensure that we’re making a valid URL. Spaces and other special characters are turned into things such as %20.

NSDictionary *headers = [NSDictionary dictionaryWithObject:
  [self userAgent] forKey:@"User-Agent"];
[request setAllHTTPHeaderFields:headers];

We add a custom User-Agent header to the HTTP request. The MusicBrainz API requires this. All requests should “have a proper User-Agent header that identifies the application and the version of the application making the request.” It’s always a good idea to play nice with the APIs you’re using, so we construct a User-Agent header that looks like:

com.yourcompany.Artists/1.0 (unknown, iPhone OS 5.0, 
  iPhone Simulator, Scale/1.000000)

(I took this formula from another part of the AFNetworking library and put it into the userAgent method in the view controller.)

The MusicBrainz API has a few other restrictions too. Client applications must not make more than one web service call per second or they risk getting their IP address blocked. That won’t be too big of an issue for our app — it’s unlikely that a user will be doing that many searches — so we take no particular precautions for this.

Once we have constructed the NSMutableURLRequest object, we give it to AFHTTPRequestOperation to perform:

AFHTTPRequestOperation *operation = [AFHTTPRequestOperation 
  operationWithRequest:request completion:^(NSURLRequest *request, 
  NSHTTPURLResponse *response, NSData *data, NSError *error)
  {
    // ...

  }];

  [queue addOperation:operation];

AFHTTPRequestOperation is a subclass of NSOperation, which means we can add it to an NSOperationQueue (in the queue variable) and it will be handled asynchronously. Because of the HUD, the app ignores any user input while the request is taking place.

We give AFHTTPRequestOperation a block that it invokes when the request completes. Inside the block we first check whether the request was successful (HTTP status code 200) or not. For this app we’re not particularly interested in why a request failed; if it does we simply tell the HUD to dismiss with a special “error” animation. Note that the completion block is not necessarily executed on the main thread and therefore we need to wrap the call to SVProgressHUD in dispatch_async().

		if (response.statusCode == 200 && data != nil)
		{
			. . .
		}
		else  // something went wrong
		{
			dispatch_async(dispatch_get_main_queue(), ^
			{
				[SVProgressHUD dismissWithError:@"Error"];
			});
		}

Now for the interesting part. If the request succeeds, we allocate the searchResults array and parse the response. The response is XML so we use NSXMLParser to do the job.

			self.searchResults = [NSMutableArray arrayWithCapacity:10];

			NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
			[parser setDelegate:self];
			[parser parse];
			[parser release];

			[self.searchResults sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

You can look up the logic for the XML parsing in the NSXMLParserDelegate methods, but essentially we just look for elements named “sort-name”. These contain the names of the artists. We add those names as NSString objects to the searchResults array. When the XML parser is done, we sort the results alphabetically, and then update the screen on the main thread:

dispatch_async(dispatch_get_main_queue(), ^
{
    [self.soundEffect play];
    [self.tableView reloadData];
    [SVProgressHUD dismiss];
});

That’s it for how the app works. It’s written using manual memory management and doesn’t use any iOS 5 specific features. Now let’s convert it to ARC.

Contributors

Over 300 content creators. Join our team.