I am getting confused with use of self inside blocks, I go through some of Apple\'s documents but still cannot find the right answer.
Some people always say use weak
You should only use a weak reference to self
, if self
will hold on to a reference of the block.
In your example, you are not keeping a reference to your block in self
, you are only using blocks inline with the UIView animateWithDuration:
, and as such there is no need to use __weak myViewController *weakSelf = self;
Why is this the case? Because a block will retain strong references to any variables it uses from the class using the block. This includes self
. Now if the class instance itself keeps a strong reference to the block, and the block keeps a strong reference to the class instance, you have a retain cycle, which will cause memory leaks.
Here's some code that demonstrates @WDUK's answer:
typedef void (^SimpleBlock)();
@interface ObjectThatRetainsBlock : NSObject
@property(nonatomic, strong) SimpleBlock block;
@end
@implementation ObjectThatRetainsBlock
- (instancetype)init {
self = [super init];
if (self) {
self.block = ^{ NSLog(@"Running block in %@", self); };
self.block();
}
return self;
}
- (void)dealloc {
NSLog(@"ObjectThatRetainsBlock is deallocated.");
}
@end
@interface ObjectThatDoesNotRetainBlock : NSObject
@end
@implementation ObjectThatDoesNotRetainBlock
- (instancetype)init {
self = [super init];
if (self) {
SimpleBlock block = ^{ NSLog(@"Running block in %@", self); };
block();
}
return self;
}
- (void)dealloc {
NSLog(@"ObjectThatDoesNotRetainBlock is deallocated.");
}
@end
- (void)test {
ObjectThatRetainsBlock *objectThatRetainsBlock =
[[ObjectThatRetainsBlock alloc] init];
ObjectThatDoesNotRetainBlock *objectThatDoesNotRetainBlock =
[[ObjectThatDoesNotRetainBlock alloc] init];
}
The test
method prints:
Running block in <ObjectThatRetainsBlock: 0x7f95f3335e50>
Running block in <ObjectThatDoesNotRetainBlock: 0x7f95f3335c50>
ObjectThatDoesNotRetainBlock is deallocated.
Observe that in the init
method of ObjectThatDoesNotRetainBlock
, we create block
as an ivar, but when the block
goes out of scope, we don't keep a reference to it.
In the test
method, when the two objects go out of scope, observe that objectThatDoesNotRetainBlock
is deallocated because it is not part of a retain cycle.
On the other hand, objectThatRetainsBlock
does not get deallocated, because it is part of a retain cycle. It retains the block beyond the scope of the method call.
If you want an another explanation, see this answer.