Automatic reference counting (Automatic Reference Counting, ARC) for Objective-C was introduced by Apple back in 2011 for iOS 4.0 and higher, Mac OS X 10.6 and higher, using xCode 4.2 and higher. And, although more and more libraries, frameworks and projects are being used by ARC today, there is still a rejection of this technology among programmers, or its incomplete understanding. Experienced programmers who are accustomed to retain / release sometimes find that they are better and more efficient in coping with reference counting than the compiler does for them, and newbies who immediately use ARC, they think they don’t need to think about memory management at all, and everything will be magically done by itself.
ARC is not a garbage collector
Unlike the garbage collector, ARC does not automatically release memory from used objects and does not start any background processes. All he does is analyze and put
retain / release into compiled code for the programmer when building the application.
You cannot directly call
retain, release, retainCount, autorelease.You can override dealloc, but you do not need to call
[super dealloc] , ARC will do this for you, and it will also release all property and instance variables that need it. It is sometimes necessary to override
dealloc in order to, for example, unsubscribe from notifications, remove an object from other services and managers to which it is subscribed, disable timers, and also release non-Objective-C objects.
Code without ARC:
- (void)dealloc { [_someIvar release]; [_anotherIvar release]; [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; }
Code from ARC:
- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
Strong and weak links
Instead of
retain and
assign attributes for
properties , ARC uses
strong and
weak attributes (
__strong and
__weak for local variables and
ivars ). These are not exactly their analogs, but more on that later. The
strong attribute is used by default, so it is not necessary to specify it explicitly.
@property AnyClass *strongReference;
Properties whose variables refer to objects “up” in the hierarchy and delegates should be weak to avoid circular references.
Since local variables are strong by default (
__strong ), such constructions are possible in the code:
NSDate *originalDate = self.lastModificationDate; self.lastModificationDate = [NSDate date]; NSLog(@"Last modification date changed from %@ to %@", originalDate, self.lastModificationDate);
The object stored in the variable
originalDate will remain alive until ARC finds the last line where this variable is used, and then immediately releases it (substitutes
release ).
')
To create a weak link, use the
__weak attribute:
NSDate * __weak originalDate = self.lastModificationDate; self.lastModificationDate = [NSDate date];
In this example, the originalDate may no longer exist on the second line, if this object is no longer strong links.
An important and useful feature of ARC: immediately after the deployment, weak links are zeroed, that is, become equal to nil.And since in Objective-C,
nil can receive any messages, problems with
EXC_BAD_ACCESS are a thing of the past. This is in contrast to the attributes of
retain / assign . The same thing happens when objects are declared: they are implicitly initialized by
nil ' ohm. A useful technique is to cache weak
properties in strong local variables, to be sure that the object will live for the necessary time:
- (void)someMethod { NSObject *cachedObject = self.weakProperty; [cachedObject doSomething]; [cachedObject doSomethingElse]; }
For the same reason, when checking weak
properties for
nil , for example, delegates, you need to cache them:
id cachedObject = self.delegate; if (cachedObject) { [self.delegate doSomeTask]; } cachedObject = nil;
Assigning to a cached object
nil removes a strong link, and if there are no other strong links to it anymore, the object will be distributed.
In rare cases, it is necessary that references to an object after its destruction are not reset. For this, there is an
unsafe_unretained attribute:
@property (unsafe_unretained) NSObject *someProperty; NSObject *__unsafe_unretained someReference;
Autorelease
Objects created using static methods (for example:
[NSData data ...], [NSArray array ...] , etc.) and literals (
@ "string", @ 42, @ [], @ {} ) no longer authorialize. The lifetime of such objects is given only by strong references to them.
There is an attribute
__autoreleasing , which, according to the documentation, it is recommended to use for double pointers (* id) in case you need to pass the result to the parameter.
NSError *__autoreleasing error; BOOL ok = [database save:&error]; if (!ok) {
Then the save method must have the following signature:
- (BOOL)save:(NSError * __autoreleasing *) error;
This ensures the safety of the object created inside the method. If you declare a variable without this attribute, the compiler will create a temporary authorization variable that will be passed to the method:
NSError * error; NSError *__autoreleasing tmp; BOOL ok = [database save:&tmp]; error = tmp;
NSAutoreleasePool is no longer available for direct use. Instead, it is proposed to use the
@autoreleasepool {} directive. When entering such a block, the state of the pool is saved, when exiting it is restored, freeing all objects created inside. It is recommended to use
@autoreleasepool in cycles if a large number of temporary objects are created.
for (id object in hugeArray) { @autoreleasepool {
Blocks
Blocks still need to be copied.
The compiler warns about circular references:
warning: capturing 'self' strongly in this block
[-Warc-retain-cycles, 4] SomeBlockType someBlock = ^{ [self someMethod]; };
When a block is copied, it will also capture
self if it uses
instance varisbles .
To avoid such cases, you need to create a weak link to
self :
__weak SomeObjectClass *weakSelf = self; SomeBlockType someBlock = ^{ SomeObjectClass *strongSelf = weakSelf; if (strongSelf) { [strongSelf someMethod]; } };
You must take care of any objects in blocks declared from the outside, using the
__weak attribute.
Build bridges
What about
CoreFondation objects? For them, the manual reference counting has not been canceled. Direct caste now does not work, for this there are several special keywords.
id my_id; CFStringRef my_cfref; NSString *a = (__bridge NSString*)my_cfref; CFStringRef b = (__bridge CFStringRef)my_id; NSString *c = (__bridge_transfer NSString*)my_cfref;
- __bridge Leaves the number of links to old objects unchanged. The CF object must be manually released.
- __bridge_transfer is needed to change the object type from CF to Objective-C. ARC decrements the reference count CF, so make sure it is greater than zero.
- __bridge_retained is needed to change the type of an object from Objective-C to CF. It will return a CF object with a reference count of +1. Do not forget to free the object by calling CFRelease () .
Conclusion
Use ARC. It is easier, safer and will save you time and nerves.
Links
Clang ARC Documentation SectionARC performance article