It helps not to focus on the strong
or weak
part of the discussion. Instead focus on the cycle part.
A retain cycle is a loop that happens when Object A retains Object B, and Object B retains Object A. In that situation, if either object is released:
- Object A won't be deallocated because Object B holds a reference to it.
- But Object B won't ever be deallocated as long as Object A has a reference to it.
- But Object A will never be deallocated because Object B holds a reference to it.
- ad infinitum
Thus, those two objects will just hang around in memory for the life of the program even though they should, if everything were working properly, be deallocated.
So, what we're worried about is retain cycles, and there's nothing about blocks in and of themselves that create these cycles. This isn't a problem, for example:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
[self doSomethingWithObject:obj];
}];
The block retains self
, but self
doesn't retain the block. If one or the other is released, no cycle is created and everything gets deallocated as it should.
Where you get into trouble is something like:
//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);
//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self doSomethingWithObj:obj];
}];
Now, your object (self
) has an explicit strong
reference to the block. And the block has an implicit strong reference to self
. That's a cycle, and now neither object will be deallocated properly.
Because, in a situation like this, self
by definition already has a strong
reference to the block, it's usually easiest to resolve by making an explicitly weak reference to self
for the block to use:
__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[weakSelf doSomethingWithObj:obj];
}];
But this should not be the default pattern you follow when dealing with blocks that call self
! This should only be used to break what would otherwise be a retain cycle between self and the block. If you were to adopt this pattern everywhere, you'd run the risk of passing a block to something that got executed after self
was deallocated.
//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
//By the time this gets called, "weakSelf" might be nil because it's not retained!
[weakSelf doSomething];
}];
Best Answer
No, there are definitely times where you would not want to use
[unowned self]
. Sometimes you want the closure to capture self in order to make sure that it is still around by the time the closure is called.Example: Making an asynchronous network request
If you are making an asynchronous network request you do want the closure to retain
self
for when the request finishes. That object may have otherwise been deallocated but you still want to be able to handle the request finishing.When to use
unowned self
orweak self
The only time where you really want to use
[unowned self]
or[weak self]
is when you would create a strong reference cycle. A strong reference cycle is when there is a loop of ownership where objects end up owning each other (maybe through a third party) and therefore they will never be deallocated because they are both ensuring that each other stick around.In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the
[unowned self]
or[weak self]
. So if a class owns a closure, and that closure captures a strong reference to that class, then you have a strong reference cycle between the closure and the class. This also includes if the class owns something that owns the closure.Specifically in the example from the video
In the example on the slide,
TempNotifier
owns the closure through theonChange
member variable. If they did not declareself
asunowned
, the closure would also ownself
creating a strong reference cycle.Difference between
unowned
andweak
The difference between
unowned
andweak
is thatweak
is declared as an Optional whileunowned
is not. By declaring itweak
you get to handle the case that it might be nil inside the closure at some point. If you try to access anunowned
variable that happens to be nil, it will crash the whole program. So only useunowned
when you are positive that variable will always be around while the closure is around