1. Introduction

  • Automatic Reference Counting is one of the biggest and most exciting changes introduced by ARC, WWDC 2011 and iOS 5. Using ARC, a feature of the new LLVM 3.0 compiler, is a complete solution to the manual memory management problem that iOS developers hate.

  • With ARC, the system detects when objects need to be retained, when they need to be automatically released, and when they need to be released. The compiler manages the memory of the object, inserts retain, release, and autorelease in places, and generates the correct code to automatically release or hold the object. We don’t have to worry about compiler errors at all.

2. ARC ownership modifier

The essence of “reference counting memory management” does not change in ARC, ARC just handles the relevant parts of reference counting for us automatically.

To work with objects, ARC introduces the following four variable ownership modifiers.

  • __strong: a strong pointer. By default, all object pointer variables are of strong pointer type. An object will live as long as there is a strong pointer to it.
  • __weak: A weak pointer that cannot hold an object instance. If an object has no strong pointer reference, the weak pointer reference is set to nil.
  • __unsafe_unretained: Similar to __weak, it is a weak reference relationship. The difference is that if an object has no strong pointer reference, an __unsafe_unretained reference will not be set to nil, but will become a wild pointer. __autoreleasing: Used to pass objects by reference, indicating that arguments passed in by reference (id*) are released automatically when the function returns.

2.1 __strong modifier

By default, all object ownership modifiers are of strong pointer type. In other words:

id obj = [NSObject alloc] init];
Copy the code

Is equal to:

id __strong obj = [NSObject alloc] init];
Copy the code

The corresponding memory management process is as follows:

{ id __strong obj = [NSObject alloc] init]; //obj creates and holds objects} //obj is out of scope, strong reference failure, will automatically release the held objectsCopy the code

2.2 __weak modifier

The __weak modifier is mostly used to solve the “circular reference” problem in reference counting memory management. If more than two member variables strongly reference each other, the two objects will never be released, resulting in a memory leak. A memory leak is when an obsolete object continues to exist beyond its lifetime.

For example, the following Test class generates two instance objects test0 and test1, using setOject: to create a reference to each other:

@interface Test : NSObject
{
    id __strong obj_;
}
 
- (void)setObject: (id __strong)obj;
@end
 
@implementation Test
- (id)init {
    self = [super init];
    return self;
}
 
- (void)setObject: (id __strong)obj {
    obj_ = obj;
}
@end
Copy the code
id test0 = [[Test alloc] init]; Id test1 = [[Test alloc] init]; Test1 generates and holds object B [test0 setObject: test1]; // test0 strongly references B [test1 setObject: test0]; Test1 strongly references object ACopy the code

Because both the alloc and setObject methods are strong references, two objects can strongly reference each other.

Circular references can be eliminated using the __weak modifier. Because a variable with an __weak modifier does not hold an object, the object is released when it goes out of its variable scope.

@interface Test:NSObject
{
    id __weak obj_;
}
 
- (void)setObject:(id __strong)obj;
@end
Copy the code

2.3 __unsafe_unretained modifier

As mentioned above, __unsafe_unretained is a weak reference similar to __weak. The difference is that if an object has no strong pointer reference, an __unsafe_unretained reference will not be set to nil, but will become a wild pointer.

__weak, but __unsafe_unretained?

__unsafe_unretained mainly interacts with C code. In addition, __weak consumes some performance. Using __weak requires checking whether the object is released, and some information needs to be tracked. Therefore, __unsafe_unretained is faster and consumes less CPU resources than __weak.

If an object has a large number of __weak references and the object is released, the weak table must be traversed to empty all Pointers in the table, consuming CPU resources.

In summary, choosing __unsafe_unretained provides some performance gains when the lifetime of an object is explicitly known. But __unsafe_unretained can also cause wild pointer problems.

2.4 __autoreleasing modifier

In ARC mode, we can’t explicitly use autorelease, but the autorelease mechanism still works. We can assign objects to the __autoreleasing modifier, The same effect can be achieved by calling the object’s autoRelease method in MRC mode.

A variable with an __autoreleasing modifier is not a local variable. Autoreleasepool is responsible for its lifetime and ensures that the object exists until @Autoreleasepool ends.

@autoreleasepool{
    id __autoreleasing obj = [[NSObject alloc] init];
}
Copy the code

The above code registers the NSObject class object into the AutoReleasepool thread pool. The source code of the simulator is as follows:

id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);
Copy the code

Objects decorated with __autoreleasing are registered in the Autorelease Pool and released when the Autorelease Pool is destroyed, just like MRC Autorelease.

3. Use of ARC

In the days of MRC, we needed to call the retain method ourselves to hold an object, which is now not required. The only thing we need to do is use a pointer to the object, and as long as the pointer is not null, the object will remain on the heap. When we point to a new object, the original object will be released once. Specific usage is as follows:

Person *p = [[Person alloc] init]; Person *p = [Person alloc] init]; Person *p = [Person alloc] init]; return 0; }Copy the code

The p pointer now points to the Person object, which will be strongly referenced by the P pointer, and which holds the object. Until the execution of the main function is complete, the object generated by the Person class exceeds the scope of the space, at this point, P no longer holds the object, the object is also about to be destroyed, the memory is released.

4. Rules for use of ARC

  • Cannot use retain/release/retainCount/autorelease, it will cause compiler error.
  • Cannot use NSAllocateObject/NSDeallocateObject. Using NSAllocateObject will cause an error.
  • Methods that generate/hold objects must follow the following naming rules: alloc/new/copy/mutableCopy/init.
  • Dealloc cannot be explicitly called. [super dealloc] cannot be called when overwriting the parent class’s dealloc method. .
  • Use the @AutoRelease block instead of NSAutoreleasePool.

5. ARC Single object memory management

  • When a local variable is released, the object is released:
int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc] init]; } return 0; return 0; return 0; }Copy the code
  • The object is released after the pointer is cleared:
int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc] init]; p = nil; } return 0; }Copy the code
  • By default, all Pointers are strong
Int main(int argc, const char * argv[]) {@autoreleasepool {// Person *p1 = [[Person alloc] init]; __strong Person *p2 = [[Person alloc] init]; } return 0; }Copy the code
  • Use of weak Pointers Note: Do not use weak Pointers to store newly created objects.
Int main(int argc, const char * argv[]) {@autoreleasepool { __weak Person *p1 = [[Person alloc] init]; } return 0; }Copy the code

6. Memory management of multiple objects in ARC

  • ARC, like MRC, must have a strong pointer to an object in order to own it, but does not need to call Release in the dealloc method.
@interface Person: NSObject //@property (nonatomic, retain) Dog * Dog; // ARC @property (nonatomic, strong) Dog * Dog; @endCopy the code

7. ARC @property parameter

  • Strong: points to and owns the object. For OC objects, equivalent to retain in MRC.
  • Weak: indicates that the object is pointed to but not owned. For OC objects, equivalent to assign in MRC
  • Assign: Applies to basic data types. Like the MRC’s assign, it does not involve memory management.
  • Copy: Similar to strong, except that copy performs a copy operation instead of a retain operation when an object is assigned (calling setter methods).

Here’s the difference between strong and copy.

The @property argument will help us generate the corresponding setter and getter. Different modifiers generate different setters and getters.

The setter for strong retains the arguments, and the setter for copy copies the contents of the arguments.

The copy operation is different when the source object is mutable or immutable:

  • When an assignment parameter is of an immutable type (such as NSString), copy performs the same assignment as strong, but makes a shallow copy of the parameter at the same address.
  • When the assignment argument is of a mutable type (such as NSMutableString), the strong pointer still points to the original address during the assignment. A copy operation makes a deep copy of the parameters, generating a new object with a changed address.

Thus, if the assignment parameter is of a mutable type, when the assignment parameter changes, the object modified with strong also changes, because both point to the same address. An object decorated with copy does not change because the copy pointer points to a new object.

So copy is used to modify immutable objects with mutable types (NSString/NSArray/NSDictionary). This is to avoid the situation where the contents of mutable data change when assigned to immutable data.

8. Loop reference problem under ARC

  • ARC and MRC, if A owns B and B also owns A, then weak Pointers must be used on both sides.
@interface Person : NSObject @property (nonatomic, strong) Dog *dog; @end@interface Dog: NSObject //@property (nonatomic, strong) Person *owner; Weak @property (nonatomic, weak) Person *owner; @endCopy the code

| the original address