Blocks are wonderful. To avoid retain cycle you often see the weakSelf - strongSelf dance like this
__weak __typeof__(self) weakSelf = self;
self.block = ^{
__typeof__(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doSomethingElse];
};
When block is created
Block is object when it is copied
Blocks are created on the stack and will go away when their stack frame returns. While on the stack, a block has no effect on the storage or lifetime of anything it accesses.
If blocks need to exist after the stack frame returns, they can be copied to the heap and this action is an explicit operation. This way, a block will gain reference-counting as all objects in Cocoa. When they are copied, they take their captured scope with them, retaining any objects they refer
Blocks can capture values from the enclosing scope
As well as containing executable code, a block also has the ability to capture state from its enclosing scope. Note that block captures the variable along with its decorators (i.e. weak qualifier),
=> This explains why you need to declare self as __weak
When block is executed
When block is executed, it is possible for weakSelf to be non-nil for the first method (doSomething), but not for the second (doSomethingElse)
You may think, at first, this is a trick to use self inside the block avoiding the retain cycle warning. This is not the case. The strong reference to self is created at block execution time while using self in the block is evaluated at block declaration time, thus retaining the object.
For best practice, however, you should create a strong reference of your object using the weak one. This won't create a retain cycle either as the strong pointer within the block will only exist until the block completes (it's only scope is the block itself).
=> This explains why you need to declare another __strong self
More explanation
This is my answer to reader Nikita
As many people point out, "Blocks are created on the stack and will go away when their stack frame returns. While on the stack, a block has no effect on the storage or lifetime of anything it accesses."
Even if block (declared on the stack) increase reference count to all the object it accesses, this would be useless, because this block will be discard when function returnsWhen block are copied (You see that people usually declare property (copy) for block), it will increase reference count to all the objects it accesses.
Why? because block are mean to be executed at a later time, so it need to keep strong reference to all the object it access. Block can be executed MANY TIMES, so IT WON'T RELEASE self AFTER this ran.
When you nil out the block, it will be dealloc, hence it will decrease the reference count to all the objects it access.
AFNetworking nil out the block after it is called, so you don't have to use weakself inside block http://www.fantageek.com/1376/afnetworking-gotcha-2/
- So there are cases when you don't have to use weakself inside block a. Make sure the block is not copied, you simply declare and run it b. Make sure the block is nil out after it is called
Reference
- I finally figured out weakSelf and strongSelf
- Working with Blocks
- Objective-C Blocks Caveat
- Objective-C Blocks Under the Hood
- A look inside blocks: Episode 1
- A look inside blocks: Episode 2
- A look inside blocks: Episode 3
- From C Declarators to Objective-C Blocks Syntax
- The Syntax of Objective-C Blocks
- Referring to weak self inside a nested block
- Capturing My(self)
❤️ Support my apps ❤️
- Push Hero - pure Swift native macOS application to test push notifications
- PastePal - Pasteboard, note and shortcut manager
- Quick Check - smart todo manager
- Alias - App and file shortcut manager
- My other apps
❤️❤️😇😍🤘❤️❤️
Top comments (0)