First of all, when you think about releasing objects in iOS, you usually think about reference counting0Determines whether the object is to be reclaimed. Declare a temporary variable that holds the address of an object that has been allocated space in the heap. The creation and release of Pointers to existing stack areas is controlled by the system, whereas heap objects need to be created and destroyed manually.
__weak, __strong, and __unsafe_unretained modifiers affect the reference counting of objects
Let’s start with an unmodified piece of code like this:
Person * p2; { Person * p = [[Person alloc] init]; Person * p1 = p; p2 = p; NSLog(@"p reference count -- --%ld",CFGetRetainCount((__bridge CFTypeRef)(p))); NSLog(@"p1 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p1))); NSLog(@"p2 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p2))); } NSLog(@"p2 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p2))); NSLog(@"p2 = %@",p2);Copy the code
Print the result
And you can see thatpA reference to is always3And there is no objection here because3Each stack pointer points to the same memory address, and the reference count becomes3There is one caveat here, the code is inpThe object declaration is preceded by a pair{}The purpose of this ispThe needle is going out{}Will be destroyed by the system, then,P, p1After the pointer is destroyed, the reference count of the heap memory object to which it points will correspond– 1, notice the printed reference count value in the red boxp2Reference this block of memory. The reference count for the object is not clear0, so, the first print isp2Object destruction is then triggered.
__strongThe program’s default variable modifier is__strong, so, the printed result is the same as that without the modifier.
__strong Person * p2; { Person * p = [[Person alloc] init]; Person * p1 = p; p2 = p; NSLog(@"p reference count -- --%ld",CFGetRetainCount((__bridge CFTypeRef)(p))); NSLog(@"p1 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p1))); NSLog(@"p2 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p2))); } NSLog(@"p2 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p2))); NSLog(@"p2 = %@",p2);Copy the code
Print the result
__weakmodified
__weak Person * p2; { Person * p = [[Person alloc] init]; Person * p1 = p; p2 = p; NSLog(@"p reference count -- --%ld",CFGetRetainCount((__bridge CFTypeRef)(p))); NSLog(@"p1 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p1))); NSLog(@"p2 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p2))); } NSLog(@"p2 = %@",p2);Copy the code
Print the following
First, there is a slight problem. The p2 reference count with __weak modifier is still 3. It can be interpreted that the system creates a temporary variable when using __weak modifier objects. 3 is printed here, but it does not affect the final result of the program because the temporary variable is destroyed in time. It is important to point out that the reference count of an object property is incremented by one when the. Syntax is used or when the set method is used, but the incremented reference count is not -1 after the code has executed, but it does not affect the object’s release.
Second, the Person object was destroyed first, and p2 = null was printed. The Person object was destroyed when it came out of the {} scope, so it was destroyed first. The __weak p2 was set to nil. Sending messages to nil doesn’t crash on iOS.
__unsafe_unretainedmodified
__unsafe_unretained Person * p2; { Person * p = [[Person alloc] init]; Person * p1 = p; p2 = p; NSLog(@"p reference count -- --%ld",CFGetRetainCount((__bridge CFTypeRef)(p))); NSLog(@"p1 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p1))); NSLog(@"p2 reference count --%ld",CFGetRetainCount((__bridge CFTypeRef)(p2))); } NSLog(@"p2 = %@",p2);Copy the code
Print the following
First, the P2 reference count does not increase by 1 as __weak does, and again, p2 crashes when printing out of the scope of the Person object.
__unsafe_unretained modified variables do not set to nil after object destruction, so the program accessed wild Pointers and crashed.
The effect of blocks on reference counting
Person * p = [Person alloc];
void(^block)(void) = ^{
NSLog(@"p---%ld",CFGetRetainCount(( __bridge CFTypeRef)(p)));
};
block();
Copy the code
Print the following
The reference count for Person here is 3,
Two questions: 1. Why is the reference count 3? The object is destroyed. Is there no circular reference?
What does the block do to the Person object? Print the address information
Person * p = [Person alloc]; NSLog(@"block stack p address = %p,p heap memory address = %p",&p,p); Void (^block)(void) = ^{NSLog(@" p = %p,p = %p",&p,p); NSLog(@"p---%ld",CFGetRetainCount(( __bridge CFTypeRef)(p))); }; block();Copy the code
Print the following
The memory address of the heap has not changed, but the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed, and the address of the pointer has changed. But the method itself will automatically decrement the reference count when it ends. It copies a pointer to the same memory address as the Person object, and the reference count is again +1. Once the block is executed, the reference count of the object is +2.
Why does it not lead to circular references?
The Person object does not hold a block, they do not refer to each other, and the Person object can be freed after the block is executed, so there is no problem with circular references.
The block above is of type NSMallocBlock. Modify the block with __weak to NSStackBlock and see what happens.
The block will be destroyed after the assignment, but the block will not be freed until the call is completed, so the warning is that the block can be found in the memory address of the heap after the __weak modifier block. It will not be released immediately after assignment.
Print the following
First, the block becomes an NSStackBlock, and the address of the Person object in the block is changed from the heap address to the stack address. The reference count of the Person object is 2. It is assumed that the reference count is not increased inside the code block.
Blocks of the NSStackBlock type are rarely used because they are released once called, but most business scenarios require blocks to be capable of handling logic at any time. Blocks of the NSStackBlock and NSMallocBlock types are objects in nature, and their memory addresses are in the heap. However, different types determine when blocks are released.
This paper is just thinking and summarizing, there are not welcome Pointers, learn from each other.