Automatic Reference Counting (ARC) in iOS (Part 2)

iOS SDKIn my last blog post, I wrote about ARC and discussed in detailed the __strong and __weak qualifiers, which should cover 80% or more of the use cases out there. In this article, I am going to complete the series by discussing the other two ARC ownership qualifiers __unsafe_unretained and __autoreleasing.

The __unsafe_unretained Qualifier

Variables qualified with __unsafe_unretained are telling the compiler that they do not want to participate in ARC at all. Hence the programmer is responsible for allocating/releasing memory and for handling object lifetimes.

Qualifiers __unsafe_unretained and __weak are actually similar in function. They both claim no ownership of any object that the variables are assigned to (hence “__unretained”) but merely act as a reference the objects. The key difference is that while a __weak variable is assigned to nil after the referenced object is released, a __unsafe_unretained variable to the same object still points to the memory space that was allocated to the object. Because of this, you can’t safely infer if an object has been of disposed with __unsafe_unretained (hence “__unsafe”).

One scenario where you would use __unsafe_unretained is when you declare a data member in a C-struct or union as an Objective-C object like NSString. See below:

struct MyStruct {
  NSString *text; // Won't compile.
}

You will get an error when you compile the code above. Under ARC, NSObject types can’t be members of a C-struct. This is because the compiler can’t manage the lifetime of a C-struct as it can’t determine the lifetime of a struct member. Therefore the developer must manage  the ownership of the Objective-C object manually (usually through CFRetain and CFRelease). Read here for a full explanation on the use of __unsafe_unretained in C-struct and the compiler error “ARC forbids Objective-C objects in structs or unions.”

struct MyStruct {
  NSString __unsafe_unretained *text; // Now it compiles.
};

The __autoreleasing Qualifier

From Apple document Transitioning to ARC Release Notes: “__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.”

The __autoreleasing qualifier is used to track objects created outside the scope of the caller but still be “retained” so that the object can be accessed by the caller. __autoreleasing is typically used in a method (eg. see method doSomething: below) that returns a BOOL to indicate if the method call is successful or not. If the method fails, we can then access the NSError object for details of the failure. The NSError object is created in the method and returned as an __autoreleasing object to the caller.

@interface MyClass : NSObject
- (BOOL)doSomething:(NSError * __autoreleasing *)myError;
@end

// ...

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    MyClass *obj = [[MyClass alloc] init];

    NSError * __autoreleasing error = nil;
    NSError * __autoreleasing * ptrToError = &error;

    [obj doSomething:ptrToError];

    // This following works as well. I used a more complex approach
    // above to illustrate the intricacies of __autoreleasing.
    [obj doSomething:&error];
  }
}

How should we implement doSomething:? If the following won’t work.

- (BOOL) doSomething:(NSError * __autoreleasing *)myError {
  NSError *error = [[NSError alloc] init];
  myError = &error;

  // ...

  return NO;
}

The problem is that the object variable error is declared implicitly as __strong. And when error varialbe goes out of scope after the control flow leaves doSomething, the error object will be disposed. This won’t work if we want to retain error so that it can be passed back to the caller. To make it work, qualify error with __autoreleasing.

NSError __autoreleasing *error = [[NSError alloc] init];
myError = &error;

Or simply do the following:

- (BOOL) doSomething:(NSError * __autoreleasing *)myError {
  *myError = [[NSError alloc] init];

  // ...

  return NO;
}

By qualifying the parameter myError as __autoreleasing, we ensure that the NSError object created in doSomething is assigned to the autorelease pool and can be safely assigned to an object variable when the control flow is returned back to the caller.

Last but not least, note that all id * is implicitly qualified with __autoreleasing.

Reference and Further Reading

Automatic Reference Counting (ARC) in iOS (Part I)

iOS SDKPrior to iOS 5 SDK, memory management in Objective-C is a manual process where developers are solely responsible for handling memory allocation and release, and object lifecycles. Apple introduced Automatic Reference Counting (or ARC) in iOS 5 to simplify memory management and made memory management the job of the new LLVM compiler.

Objective-C Memory Management Policy

The best way to understand memory management in Objective-C is to think of object ownership (see Memrory Management Policy for more info). Here are the rules to memory management prior to ARC:

  • You own any object you create – Method names that include alloc, new, copy, or mutableCopy creates an object
  • You can take ownership of an object using retain – An object can have more than 1 owner
  • When you no longer need it, you must relinquish ownership of an object you own – As long as an object has 1 owner, it continue to exist. Ownership to the object is relinquished by calling release. When an object is no longer owned, it gets disposed by the system
  • You must not relinquish ownership of an object you do not own – This is a conventional rule. Break this rule and the app may crash

These rules still apply to ARC even though retain, release, and autorelease are no longer supported in the new model. In ARC the rules are fulfilled automatically in the background and is primarily handled by the compiler. The key to understanding ARC is to distinguish the difference between an object and an object (pointer) variable referencing that object. As soon as there are no owners (or variables pointing) to an object, the system disposes that object. Also it is important to note that there’s no garbage collection in Objective-C. ARC is a compiler-time feature where the compiler analyzes code and insert code to track the lifecycles of objects.

When an object (NSObject type or its subclass) is created, we can assign the object to a variable. In ARC, an object variable can have one of the following 4 ownership qualifiers:

  • __strong
  • __weak
  • __unsafe_unretained
  • __autoreleasing

In this blog post, we will review the first two qualifiers __strong and __weak in detail and save the latter two in the next blog post.

The __strong Qualifier

__strong is akin to retain in non-ARC and it’s the default qualifier of an object variable if no ownership qualifier is specified. The following code snippets are identical.

- (void)nonARC {
  id obj = [[MyClass alloc] init];
  [obj release];
}

- (void)ARC {
  // Obj has a strong reference to MyClass object so it owns
  // MyClass object.
  id obj = [[MyClass alloc] init];

  // When the object variable goes out of scope, the owner
  // is discarded and consequently relinquishing ownership of
  // MyClass object.
}

For __strong qualifier, we rely on variable assignment and the end of a variable scope to gain and relinquish object ownership respectively.

The __weak Qualifier

The __weak qualifier is akin to the assign keyword in non-ARC and is typically used to reference an object but claims no ownership on that object. A __weak qualified variable is automatically assigned to nil (effectively disposing the pointer variable) after the object it is pointing to is released. We can perform a conditional check on a __weak qualified variable. If the variable is nil, we know that the referenced object has already been disposed.

__weak qualified variable is useful for for referencing up a parent-child object hierarchy ie. a child object should only establish a weak reference to its parent. For example, a table view can be implemented in iOS by creating a UITableView object and assign it to a UIViewController. Both objects reference each other. UIViewController references UITableView via the view property while UITableView references UIViewController via the delegate property. If we qualify all referencing properties as __strong, we will get into a circular reference situation. Under such circumstances, even though the referencing object variables have gone out of scope, the objects themselves are still not properly disposed. Due to the circular strong reference, the system still thinks that the 2 objects are owned, leading to memory leaks. A detailed explanation of circular reference is available here.

Reference reference between UITableView and UIViewController

The best way to handle circular reference especially if there’s a clear parent-child object relationship is to use a strong/weak reference pattern. UIViewController owns the UITableView object, so it makes sense to qualify this reference with a __strong qualifier. On the other hand, the delegate property in UITableView should be qualified as __weak given that UITableView doesn’t own UIViewController but merely referencing it.

We will talk about __unsafe_unretained and __autoreleasing qualifiers in the next blog post.

Reference

HTTP basic access authentication with Objective-C and iOS

iOS SDKIn this blog post I am going to show how you can make an HTTP request to a webserver that supports basic access authentication using Objective-C and the iOS framework. Regretfully, I don’t have the time to create an Xcode project as an example. But the information and code should give you an idea of how you can build basic access authentication support in your iOS code.

Before we dive into the code, let’s do a quick review of how basic access authentication works. Before an HTTP request is sent to the server, we need to append an HTTP header called Authorization to the request. Here are the steps to generating the Authorization HTTP header:

Using username = myusername and password = mypassword as reference.

  1. Concatenate user name + colon + password. ie. “myusername:mypassword”
  2. Encode the concatenated string with the base64 algorithm. ie. “myusername:mypassword becomes” “bXl1c2VybmFtZTpteXBhc3N3b3Jk”
  3. Append the Base64 encoded string to the “Basic ” string. ie. “Basic bXl1c2VybmFtZTpteXBhc3N3b3Jk”
  4. Finally assign the value to the Authorization header

In Objective-C code, the above logic is translated to:

NSString *authStr = [NSString stringWithFormat:@"%@:%@", @"myusername", @"mypassword"];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:@"Basic %@", [authData base64Encoding]];
[request setValue:authValue forHTTPHeaderField:@"Authorization"];

Just one problem, NSData doesn’t inherently support Base64 encoding. We need to add Base64 encoding algorithm to NSData via Category, a mechanism Objective-C that allows programmers to extend an existing class without subclassing it. Anyway, you can download the Base64 encoding code below.

NSData+Additions source code

Credits and Reference:

Note that you can certainly implement Base64 encoding using C functions or by other means. But I find Category most intuitive to achieving our goal.

Tip
If you are still stuck, use the curl command on a shell to troubleshoot. Here are some examples:

% curl -v -H 'Authorization: Basic bXl1c2VybmFtZTpteXBhc3N3b3Jk' 'http://host/path'

% curl -v --trace-ascii dump.txt 'http://myusername:mypassword@host/path'

Creating multi-variants of an iOS app from a single Xcode project

iOS SDKWhen someone at work asked me about creating multiple variants of an iOS app  from a common codebase (ie. from a single Xcode project), I thought couldn’t this be achieved through defining multiple targets in that Xcode project?

I have done this before for a project where I created a “lite” version and an “HD” (iPad-only) version from a full-featured iPhone codebase I originally created. I was about to document the process on this post before coming across this blog post from Just2Us, which does a great job in explaining the entire process. Instead of duplicating the content, just refer to the blog post.

One thing I would do differently from what is described in the referenced post is that instead of adding a new target, I would recommend duplicating an existing target – this way I avoid the hassle of configuring the new build target and including the files to my target phases manually.

Duplicating a build target in Xcode

I have also created a project to demonstrate the multi-target in Xcode. You can download the file here.

Quick guide to iOS dateformatting

iOS SDK

This blogpost will focus on the setDateFormat: method of NSDateFormatter which allow us to define the date format of the textual representation of the date and time in iOS/Cocoa. Here’s a summary of the specifiers used in the date format string.

The most commonly used date format specifiers are (keep in mind that they are case sensitive):

  • y = year
  • Q = quarter
  • M = month
  • w = week of year
  • W = week of month
  • d = day of the month
  • D = day of year
  • E = day of week
  • a = period (AM or PM)
  • h = hour (1-12)
  • H = hour (0-23)
  • m = minute
  • s = second

In general, the number of characters in a specifier determine the size of date field. Let’s use an example to illustrate date formatting.

eg. Input date = 2011-05-01 Sunday

1-character = 1-digit/character number or word (if number/word can’t be 1 character long then abbreviation or fullname is displayed).

[dateFormatter setDateFormat:@"E, d M y"];  // Output: Sun, 1 5 2011

2-character = 2-digit/character number or word (if number/word can’t be 2 character long then abbreviation is displayed).

[dateFormatter setDateFormat:@"EE, dd MM yy"];  // Output: Sun, 01 05 11

3-character = 3-digit/character number or word, or abbreviation (generally).

[dateFormatter setDateFormat:@"EEE, ddd MMM yyy"];  // Output: Sun, 001 May 2011

4-character = full name (generally).

[dateFormatter setDateFormat:@"EEEE, dddd MMMM yyyy"];  // Output: Sunday, 0001 May 2011

Here’s the weird part though, if you specify 5 E’s, you get an rather unexpected output. You would think that the output date field would be longer than 1 character:

[dateFormatter setDateFormat:@"EEEEE, ddddd MMMMM yyyyy"];  // Output: S, 00001 M 2011

For date formatting, the following reference table has been very useful:

Date Field Symbol Table (UTS #35 Unicode Locale Data Markup Language)

Materials for my iOS frameworks talk at MobileCamp Boston

Presentation Screen IconI will be speaking at MobileCamp Boston on Feb 19, 2011 (later today). I will be giving a presentation on building RESTful iOS apps using Three20 and RESTKit frameworks. I will write a blog entry with a more detailed coverage of my talk later. For now, here are the presentation slides and the TwitterReader Source Code I will use at the talk. Enjoy.

Icon credits: Jack Cai

TTTableViewController showMenu:forCell: example

iOS SDKA week ago, I was looking for ways in Three20 to create an animated row menu similar to the behavior in the Facebook app where a the table cell switches to a view with a “Like” and a “Comment” button. Upon more investigation, I discovered showMenu:forCell: in TTTableViewController that does exactly what I am looking for. Unfortunately Three20 documentation and samples shed little light on how showMenu:forCell: should be used. I also googled around and found a simple example and found this post on Three20 discussion thread on Google Groups, which was enough to get me started in right direction.

iPhone table view iPhone table view show menu

I messed around with the code further and came up with a more coherent technique in creating the animated show menu effect using showMenu:forCell: Here’s a snippet of the same code demonstrating how you can trigger the menu view by swipe gesture.

- (void) viewDidLoad {
  // Register the swipe gesture.
  UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc]
                                          initWithTarget:self
                                          action:@selector(swipeDidOccur:)];
  [recognizer setDirection:(UISwipeGestureRecognizerDirectionRight |
                            UISwipeGestureRecognizerDirectionLeft)];
  [self.view addGestureRecognizer:recognizer];
  [recognizer release];

  [super viewDidLoad];
}

- (void) swipeDidOccur:(UISwipeGestureRecognizer *)recognizer {
  // Get the start point so that we can do a hit test on the table view.
  CGPoint startPoint = [recognizer locationInView:self.tableView];
  NSIndexPath *path = [self.tableView indexPathForRowAtPoint:startPoint];
  TTTableViewCell* cell = (TTTableViewCell*) [self.tableView
                                              cellForRowAtIndexPath:path];

  // Add menuView to the cell.
  UIView *menuView = [[UIView alloc] initWithFrame:cell.contentView];

  // Now call showMenu with the menu to display on the associated cell.
  [self showMenu:menuView forCell:cell animated:YES];
  [menuView release];
}
The code relies on detecting swipe touch gesture on TTTableViewController and using a selector to handle the gesture. Given a gesture touch point, you can determine the cell where the swipe occurred. Once you have a reference to a cell, you can call the showMenu:forCell:
What if we need to trigger the menu view by touch a button on the table view cell? This is what I did:
Create a subclass of TTTableViewCell and add a UIButton to the view.

The code relies on detecting swipe touch gesture on TTTableViewController and using a selector to handle the gesture. Given a gesture touch point, you can determine the cell where the swipe occurred. Once you have a reference to a cell, you can call the showMenu:forCell:
What if we need to trigger the menu view by touch a button on the table view cell? This is what I did:

Create a subclass of TTTableViewCell and add a UIButton to the view.

@interface MyViewCell : TTTableViewCell {
}

- (id) initWithName:(NSString *)name target:(id)target action:(SEL)action {
  // ...

  UIButton *moreButton = [UIButton buttonWithType:UIButtonTypeCustom];
  moreButton.frame = CGRectMake(268.0f, 6.0f, 32.0f, 32.0f);
  [moreButton setImage:TTIMAGE(@"bundle://Icon_More.png")
              forState:UIControlStateNormal];
  [moreButton addTarget:target action:action
       forControlEvents:UIControlEventTouchUpInside];
  [self moreButton];

  // ...
}

Next, create a subclass of TTTableViewController and add the custom TTTableViewCell to the data source.

@interface MyTableViewController : TTTableViewController {
}

- (void) createModel {
  self.dataSource = [TTListDataSource dataSourceWithObjects:
    [[[ContactViewCell alloc] initWithName:@"Cell 1"
                                    target:self
                                    action:@selector(plusButtonDidPress:)]
                                    autorelease],
    [[[ContactViewCell alloc] initWithName:@"Cell 2"
                                    target:self
                                    action:@selector(plusButtonDidPress:)]
                                    autorelease],
    nil];
}

In the action handler, that’s where showMenu:forCell: is called. The trick is to determine which cell the button belongs to and consequently replace that cell withe the menu view. This is how I did.

- (void) plusButtonDidPress:(id)sender {
  // Load our custom menu view from a nib.
  UIView *menuView = [[UIView alloc] initWithFrame:cell.contentView];

  UIButton *moreButton = (UIButton *) sender;
  // Convert plusButton bounds to the the coordinate system of table view
  // and then get the cell containing the button.
  CGRect coord = [plusButton convertRect:moreButton.bounds toView:self.tableView];
  NSIndexPath *path = [self.tableView indexPathForRowAtPoint:coord.origin];
  TTTableViewCell* cell = (TTTableViewCell*) [self.tableView
                                              cellForRowAtIndexPath:path];

  // Now call showMenu with the menu to display on the associated cell.
  [self showMenu:menuView forCell:cell animated:YES];
}

Here’s the entire source code on GitHub. Enjoy.

Update

Since some of you asked, I have updated the sample on GitHub to include an example of you can “wire” the buttons on the MenuView to the appropriate action handlers.

First, create a base view controller called BaseCatalogViewController containing the action handlers and have the other 3 controllers inherit the base class. The file’s owner of MenuView.xib should be of type BaseCatalogViewController. Lastly, associate each button in MenuView.xib to an IBAction. You can find the source code at GitHub. Good luck.

Proper URL (Percent) Encoding in iOS

iOS SDKIf you are developing an iPhone app makes RESTful remote calls to a server in the Internet, you will likely need to encode your parameter to a percent encoded string (aka URL-encoding) so that you can properly embed the information in a URI before passing it to the remote server. For example, say you have an address that looks like this:

One Broadway, Cambridge, MA

Under URL encoding, the string becomes:

One%20Broadway,%20Cambridge,%20MA

To encode a string using URL-encodng, simply use following method in NSString:

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding

Conversely, you can use the following method to decode a URL-encoded string to back to its original text:

stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding

Full example:

NSString *rawText = @"One Broadway, Cambridge, MA";

NSString *encodedText = [rawText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Encoded text: %@", encodedText);
NSString *decodedText = [encodedText stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Original text: %@", decodedText);

Here’s the output:
Encoded text: One%20Broadway,%20Cambridge,%20MA
Original text: One Broadway, Cambridge, MA

But there’s just one problem, stringByAddingPercentEscapesUsingEncoding doesn’t encode reserved characters like ampersand (&) and slash (/). For example:

NSString *rawText = @"Bed Bath & Beyond - URL=http://www.bedbathandbeyond.com/";

NSString *encodedText = [rawText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Encoded text: %@", encodedText);
NSString *decodedText = [encodedText stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Original text: %@", decodedText);

Here’s the output:

Encoded text: Bed%20Bath%20&%20Beyond%20-%20URL=http://www.bedbathandbeyond.com/
Original text: Bed Bath & Beyond – URL=http://www.bedbathandbeyond.com/

As you can see, & and / (in bold red) aren’t encoded. As a workaround, use Foundation function CFURLCreateStringByAddingPercentEscapes instead (as suggested by Simon). Full example here:

// Encode a string to embed in an URL.
NSString* encodeToPercentEscapeString(NSString *string) {
  return (NSString *)
  CFURLCreateStringByAddingPercentEscapes(NULL,
                                          (CFStringRef) string,
                                          NULL,
                                          (CFStringRef) @"!*'();:@&=+$,/?%#[]",
                                          kCFStringEncodingUTF8);
}

// Decode a percent escape encoded string.
NSString* decodeFromPercentEscapeString(NSString *string) {
  return (NSString *)
  CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
                                                          (CFStringRef) string,
                                                          CFSTR(""),
                                                          kCFStringEncodingUTF8);
}

int main (int argc, const char * argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

  NSString *rawText = @"Bed Bath & Beyond - URL=http://www.bedbathandbeyond.com/";

  NSString *encodedText = encodeToPercentEscapeString(rawText);
  NSLog(@"Encoded text: %@", encodedText);
  NSString *decodedText = decodeFromPercentEscapeString(encodedText);
  NSLog(@"Original text: %@", decodedText);

  [pool drain];
  return 0;
}

And the output:

Encoded text: Bed%20Bath%20%26%20Beyond%20-%20URL%3Dhttp%3A%2F%2Fwww.bedbathandbeyond.com%2F
Original text: Bed Bath & Beyond – URL=http://www.bedbathandbeyond.com/

This time it correct encode the & and / characters. Of course, you won’t be encoding the entire URL but only the URI parameters. There’s no code download for this, simply cut the above code snippets to your code and paste to your code base.

Errata (Feb 18, 2011)

CFURLCreateStringByAddingPercentEscapes returns a string reference with a retain count of +1. So remember to release it when you are done using it.