Why strongSelf and weakSelf?
Before talking about strongSelf and weakSelf, I need briefly explain retain cycle.
So, a retain cycle usually occurs when an object A has a strong reference to Object B, and Object B also has a strong reference to Object A. Under this situation, the retainCount for both objects can not be 0, so the memory for these two objects won’t be released. This is the memory leak. The retain cycle could happen between multiple objects as long as their references between each other form a cycle.
Also, an object can have a reference of itself which will cause retain cycle too. The most common situation is that an object owns a block, and in the block, we call any of this object’s methods or properties. Then the block has a reference to this object itself, which cause a retain cycle. Notice that blocks maintain strong references to any captured objects, including self, because they don’t want data be destroyed by ARC before themselves getting executed.
Example 1:
I have an object called Car. Car has a block called drive.
1 | // car.h |
In the viewController.
1 |
|
Leak! Here, the car has a strong reference to the drive block, and in the block, the block has a strong reference to the car since we called car.miles. This made the car has a reference to itself.
Using Instruments to detect the leak. Click the red cross. Malloc 48 Bytes means the system allocate 48 Bytes of memory to the block.
Open Cycles & Roots. You can see the cycle.
Change the Example 1 to Example 2.
Example 2:
I pass a parameter into the block. Leak?
1 |
|
No Leak. Checking the leak with instruments:
Since I pass the car.miles into the block as a parameter, and the block won’t retain the parameter, there will be no retain cycle.
WEAKSELF AND STRONGSELF
weakSelf
How to create a weakSelf? There are two ways.
1 | __weak __typeof(self) weakSelf = self; |
1 |
|
The reason we use weakSelf in a block is that with weak property, the block won’t retain the object in the block. Then we break the cycle. For example 1, we can use weakself to solve the retain cycle problem.
1 |
|
strongSelf
1 | __strong __typeof(weakSelf) strongSelf = weakSelf; |
1 |
Since we use weakSelf in the block to prevent the retain cycle problem, there is a potential problem that the object could be released before the block has been executed.
example 3:
1 |
|
I add a delay before executing the NSlog(). Then the output is:... 15:28:20.875923 BlockTest[7630:4429580] return
... 15:28:23.065725 BlockTest[7630:4429580] Car drived (null)
What is happening here? The dispatch_after() function submits the block (which contains NSLog()) to the given queue (Here is the main queue) at the time specified by the when (Here is after 2 sec) parameter. Think the block as a task. The dispatch_after() asynchronously add the task to the main queue after two sec when you execute the study block. Since the study block has a weak reference to the car, after the study block has been execute (car.drive() is called), the weakCar is released by ARC, then the weak object will be set as nil. However, the dispatch block is still not executed. That is why we got null in the output.
So, we add strongSelf in the block which prevent the object will not be released inside the block. After the block is executed, strongSelf then release.
1 |
|