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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Beginning ARC in iOS 5 Tutorial Part 1
50 mins
AppDelegate.h
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) MainViewController *viewController;
The app delegate has two properties, one for the window and one for the main view controller. This particular project does not use a MainWindow.xib file, so these two objects are created by the AppDelegate itself in application:didFinishLaunchingWithOptions: and stored into properties in order to simplify memory management.
These property declarations change from this,
@property (retain, nonatomic)
to this:
@property (strong, nonatomic)
The strong keyword means what you think it does. It tells ARC that the synthesized ivar that backs this property holds a strong reference to the object in question. In other words, the window property contains a pointer to a UIWindow object and also acts as the owner of that UIWindow object. As long as the window property keeps its value, the UIWindow object stays alive. The same thing goes for the viewController property and the MainViewController object.
AppDelegate.m
In AppDelegate.m the lines that create the window and view controller objects have changed and the dealloc method is removed completely:
Spot the differences between this,
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
bounds]] autorelease];
and this:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]
bounds]];
That’s correct, the call to autorelease is no longer needed. Likewise for the line that creates the view controller.
self.viewController = [[[MainViewController alloc] initWithNibName:
@"MainViewController" bundle:nil] autorelease];
now becomes:
self.viewController = [[MainViewController alloc] initWithNibName:
@"MainViewController" bundle:nil];
Before ARC, if you wrote the following you created a memory leak if the property was declared “retain”:
self.someProperty = [[SomeClass alloc] init];
The init method returns a retained object and placing it into the property would retain the object again. That’s why you had to use autorelease, to balance the retain from the init method. But with ARC the above is just fine. The compiler is smart enough to figure out that it shouldn’t do two retains here.
One of the things I love about ARC is that in most cases it completely does away with the need to write dealloc methods. When an object is deallocated its instance variables and synthesized properties are automatically released. You no longer have to write:
- (void)dealloc
{
[_window release];
[_viewController release];
[super dealloc];
}
because Objective-C automatically takes care of this now. In fact, it’s not even possible to write the above anymore. Under ARC you are not allowed to call release, nor [super dealloc]. You can still implement dealloc — and you’ll see an example of this later — but it’s no longer necessary to release your ivars by hand.
Something that the conversion tool doesn’t do is making AppDelegate a subclass of UIResponder instead of NSObject. When you create a new app using one of Xcode’s templates, the AppDelegate class is now a subclass of UIResponder. It doesn’t seem to do any harm to leave it as NSObject, but you can make it a UIResponder if you want to:
@interface AppDelegate : UIResponder <UIApplicationDelegate>
Main.m
In manually memory managed apps, the [autorelease] method works closely together with an “autorelease pool”, which is represented by an NSAutoreleasePool object. Every main.m has one and if you’ve ever worked with threads directly you’ve had to make your own NSAutoreleasePool for each thread. Sometimes developers also put their own NSAutoreleasePools inside loops that do a lot of processing, just to make sure autoreleased objects created in that loop don’t take up too much memory and get deleted from time to time.
Autorelease didn’t go away with ARC, even though you never directly call the [autorelease] method on objects anymore. Any time you return an object from a method whose name doesn’t start with alloc, init, copy, mutableCopy or new, the ARC compiler will autorelease it for you. These objects still end up in an autorelease pool. The big difference with before is that the NSAutoreleasePool has been retired in favor of a new language construct, @autoreleasepool.
The conversion tool turned our main() function from this,
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
[pool release];
return retVal;
into this:
@autoreleasepool {
int retVal = UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
return retVal;
}
Not only is it simpler to read for us programmers but under the hood a lot has changed as well, making these new autorelease pools a lot faster than before. You hardly ever need to worry about autorelease with ARC, except that if you used NSAutoreleasePool in your code before, you will need to replace it with an @autoreleasepool block. The conversion tool should do that automatically for you as it did here.
SoundEffect.m
Not much changed in this file, only the call to [super dealloc] was removed. You are no longer allowed to call super in your dealloc methods.
Notice that a dealloc method is still necessary here. In most of your classes you can simply forget about dealloc and let the compiler take care of it. Sometimes, however, you will need to release resources manually. That’s the case with this class as well. When the SoundEffect object is deallocated, we still need to call AudioServicesDisposeSystemSoundID() to clean up the sound object and dealloc is the perfect place for that.
SVProgressHUD.m
This file has the most changes of them all but again they’re quite trivial.
At the top of SVProgressHUD.m you’ll find a so-called “class extension”, @interface SVProgressHUD (), that has several property declarations. If you’re unfamiliar with class extensions, they are like categories except they have special powers. The declaration of a class extension looks like that of a category but it has no name between the () parentheses. Class extensions can have properties and instance variables, something that categories can’t, but you can only use them inside your .m file. (In other words, you can’t use a class extension on someone else’s class.)
The cool thing about class extensions is that they allow you to add private properties and method names to your classes. If you don’t want to expose certain properties or methods in your public @interface, then you can put them in a class extension. That’s exactly what the author of SVProgressHUD did.
@interface SVProgressHUD ()
...
@property (nonatomic, strong) NSTimer *fadeOutTimer;
@property (nonatomic, strong) UILabel *stringLabel;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIActivityIndicatorView *spinnerView;
...
@end
As we’ve seen before, retain properties will become strong properties. If you scroll through the preview window you’ll see that all the other changes are simply removal of retain and release statements.