📜 ⬆️ ⬇️

What you need to know about ARC

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; //(atomic, strong)   @property (nonatomic, weak) id delegate; 

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.

 //property @property (nonatomic, copy) SomeBlockType someBlock; //  someBlockType someBlock = ^{NSLog(@"hi");}; [someArray addObject:[someBlock copy]]; 

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; // -1    CFRef CFStringRef d = (__bridge_retained CFStringRef)my_id; //  CFRef +1 




Conclusion


Use ARC. It is easier, safer and will save you time and nerves.

Links

Clang ARC Documentation Section
ARC performance article

Source: https://habr.com/ru/post/209288/


All Articles