Wednesday, 7 May 2014

Enabling ARC [The Elephant in the Room]

You enable ARC in your project settings. It will be turned on for all new projects. If you want to change iin an existingproject, visit the projects build settings. Find the Appl LLV  Language  Objective-C section,
and change theObjective-C  Automati Reference Counting  setting, as shown in Figure 21-10.


Figure 21-10. Changing  the ARC setting for a project

Strong and Weak References

ARC introduces two new object reference qualifiers: strong and weak. Under ARC, all object reference variables are strong by default. And this doesnt apply to just properties; all object references—property values, instance variables, automatic variables, parameter variables, and static variables—act like a retain property under ARC.

For @property declarations, the new strong attribute makes this explicit, and replaces the retain attribute. If you feel the need to explicitly declare that an instance or automatic variable is strong, use the new    strong (thatstwo underscore characters) type qualifier, like this:

-  (void)doSomething
{
id    strong value;
...

To address circular retains, and similar problems, ARC provides the weak attribute. Use weak in
place of assign in @property declarations to create a reference that does not retain the object. With variables, the    weak type qualifier will do the same.

As you’ve seen, circular retains are a perfect use for the weak qualifier. Another situation where weak is useful is in view controller outlets that refer to view objects. Throughout this book, you’ve written Interface Builder outlets thatlook like this:

@interface DDViewController  : UIViewController

@property  (weak,nonatomic) IBOutlet  UIBarButtonItem *playButton;
@property  (weak,nonatomic) IBOutlet  UIBarButtonItem *pauseButton;
@property  (weak,nonatomic) IBOutlet  UIImageView *albumView;
@property  (weak,nonatomic) IBOutlet  UILabel  *songLabel;
@property  (weak,nonatomic) IBOutlet  UILabel  *albumLabel;
@property  (weak,nonatomic) IBOutlet  UILabel  *artistLabel;

Why were all of those properties weak? A weak reference allows those view objects to be automatically released. As you’ll learn in Chapter 23, iOS may send your app warning messages when its starting trun out of memory. Viewcontrollers—that are not being displayed—react by releasing their view objects.
(view controller can always reload its view objects froits Interface Builder file.) If these properties werstrong, those view objects wouldn't be released because the individual properties would still retain themBy making them weak, oncethe view controller releases its view objects, these properties are set to nil.

There are, unfortunately, pitfalls to using the weak qualifier too. The problem is that a weak reference does not retain its object. If all of the references to an object are weak, the object gets destroyed. This was the problem youran into in the Wonderland app.
The page view controllers data source property is weak (assign), to avoid circular retains. Your natural inclination is to create your data source object and assign it to the property, like this:

self.dataSource = [WLBookDataSource new];

If you run the app, you’ll find the WLBookDataSource object is immediately destroyed again. Thats because the dataSource property is weak, and there are no other strong references to the object.

The solution was to create a second, strong, reference to the object in WLBookViewController, like this:

@interface WLBookViewController  ()
{
WLBookDataSource  *bookSource;            // strong reference to dataSource
}
@end

When the data source object is created, its assigned to both the property and the instance variable:

self.dataSource = bookSource = [WLBookDataSource new];

The mystery is finally explained. The second, strong, reference retains the data source object and keeps it alive for the lifetime of the WLBookViewController object.


What ARC Doesn’t Do

ARC is a fantastic technology, and probably the best compromise in balancing the needs of the developer with the demands of running on a mobile device. Its reach, however, stops right at the border of Objective-C. CoreFoundation (the C functions at iOSs core) also uses reference counting, but ARC takes a decidedly “hands off” approach.

You encountered this already in your ColorModel app. In the code that created the hue/saturation field image, you used some Core Graphics functions. These were C functions that returned pointers to object-like structurescalled types. Core Foundation types use reference counting too:

CGColorSpaceRef  colorSpace = CGColorSpaceCreateDeviceRGB(); CGDataProviderRef provider = CGDataProviderCreateWithCFData(
(   bridge CFDataRef)bitmapData);
hsImageRef = CGImageCreate(...); CGColorSpaceRelease(colorSpace); CGDataProviderRelease(provider);

There are two things of interest in this code. First, you’re responsible for the memory management of these
types, even though this is an ARC app. The values returned by CGColorSpaceCreateDeviceRGB andCGDataProviderCreateWithCFData are new (retained) type references. Its your responsibility to release them, using the appropriate Core Foundation release functions, CGColorSpaceRelease  and CGDataProviderRelease.

Secondly, theres that pesky rule that you cant convert an Objective-C object pointer into a C pointer. But thats exactly what happens in the parameter of CGDataProviderCreateWithCFData. The parameter is a CFDataRef (a C pointer), but bitmapData is an NSData object. CFData and NSData are functionally interchangeable, members of the toll-free bridge. A select number of classes in Objective-C have Core Foundation counterparts,
either of which can substitute for the other. The special    bridge qualifier relaxesARCs normal rules to allow the Objective-C object reference to be passed as a C type reference.

And the border between Objective-C and Core Foundation isnt completely closed. ARC has an emigration policy, of sorts. A Core Foundation function that returns a toll-free bridge type is often cast and stored in anObjective-C object reference, so it can be treated as an object. In pre-ARC code, it would look like this:

NSString   *strObj = (NSString*)CFUUIDCreateString(0,uuid);

This particular function creates a new string from a UUID structure and stores it in a string object reference. But again, ARC doesnt allow this because CFUUIDCreateString returns a CFStringRef pointer, not an object. This is fixed by adding the    bridge_transfer qualifier:

NSString   *strObj = (   bridge_transfer NSString*)CFUUIDCreateString(0,uuid);

Two wonderful things happen. The compiler stops complaining, allowing the C type pointer to be converted into an Objective-C object pointer.
But even more significant, ARC takes responsibility for releasing strObj. The   bridge_transfer qualifier says “This C pointer represents an Objective-C compatible object with a retain count of 1. Store it in an object reference and treat it like any newly created object.” ARC takes it from there.

If you need to go the other direction—taking an ARC-managed object and converting it into a Core Foundation reference—use the    bridge_retained qualifier, like this:

NSString   *objString = @"Hello!";
CFStringRef coreString  = (   bridge_retained CFStringRef)objString;
// do  C  function things with  coreString CFRelease(coreString);

ARC transfers ownership and memory management of the Objective-C object to you, as if it was a newly created CFStringRef. From there, you treat it like any CFStringRef, which includes releasing it (CFRelease)
when you’redone.

Those are the highlights of using the Core Foundation and the toll free bridge. These, and additional issues, are discussed in the Transitioning to ARC Release Notes that can be found in Xcodes Documentation and 
APIReference window.

Summary

Memory management is a critical part of successful iOS app development. With the help of technologielike ARC, you shouldnt spend too much of your day worrying about it. With your newfound knowledge
of ARC and circularetains, you can make intelligent decisions about what kinof reference to defin(strong or weak), and how to solve the occasional mystery of disappearin(weakly retained) objects. Morimportantly, you understandwhen and why objects get destroyed, which will be important for reducinyour apps memory use. In a later chapter, you’ll get tsee just how mucmemory your apis using.

But before you get to that, we’re going to take a little trip and visit a part of iOS development thats often overlooked. A place where you can ask the question “¿Qué pasa, Alicia?”

No comments:

Post a Comment