and change theObjective-C Automatic 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 doesn’t 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 (that’stwo 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 it’s starting to run out of memory. Viewcontrollers—that are not being displayed—react by releasing their view objects.
(A view controller can always reload its view objects from its Interface Builder file.) If these properties were strong, those view objects wouldn't be released because the individual properties would still retain them. By 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 controller’s 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. That’s 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, it’s 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 iOS’s 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. It’s your responsibility to release them, using the appropriate Core Foundation release functions, CGColorSpaceRelease and CGDataProviderRelease.
Secondly, there’s that pesky rule that you can’t convert an Objective-C object pointer into a C pointer. But that’s 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 relaxesARC’s 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 isn’t 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 doesn’t 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 Xcode’s Documentation and
APIReference window.
Summary
Memory management is a critical part of successful iOS app development. With the help of technologies like ARC, you shouldn’t spend too much of your day worrying about it. With your newfound knowledge
of ARC and circular retains, you can make intelligent decisions about what kind of reference to define (strong or weak), and how to solve the occasional mystery of disappearing (weakly retained) objects. More importantly, you understandwhen and why objects get destroyed, which will be important for reducing your app’s memory use. In a later chapter, you’ll get to see just how much memory your app is using.
But before you get to that, we’re going to take a little trip and visit a part of iOS development that’s often overlooked. A place where you can ask the question “¿Qué pasa, Alicia?”

No comments:
Post a Comment