Retain cycle on `self` with blocks
Strictly speaking, the fact that it's a const copy has nothing to do with this problem. Blocks will retain any obj-c values that are captured when they are created. It just so happens that the workaround for the const-copy issue is identical to the workaround for the retain issue; namely, using the __block
storage class for the variable.
In any case, to answer your question, there's no real alternative here. If you're designing your own block-based API, and it makes sense to do so, you could have the block get passed the value of self
in as an argument. Unfortunately, this doesn't make sense for most APIs.
Please note that referencing an ivar has the exact same issue. If you need to reference an ivar in your block, either use a property instead or use bself->ivar
.
Addendum: When compiling as ARC, __block
no longer breaks retain cycles. If you're compiling for ARC, you need to use __weak
or __unsafe_unretained
instead.
Just use:
__weak id weakSelf = self;[someObject someMethodWithBlock:^{ [weakSelf someOtherMethod];}];
For more information: WWDC 2011 - Blocks and Grand Central Dispatch in Practice.
https://developer.apple.com/videos/wwdc/2011/?id=308
Note: if that doesn't work you can try
__weak typeof(self)weakSelf = self;
This might be obvious, but you only have to do the ugly self
alias when you know you’ll get a retain cycle. If the block is just a one-shot thing then I think you can safely ignore the retain on self
. The bad case is when you have the block as a callback interface, for example. Like here:
typedef void (^BufferCallback)(FullBuffer* buffer);@interface AudioProcessor : NSObject {…}@property(copy) BufferCallback bufferHandler;@end@implementation AudioProcessor- (id) init { … [self setBufferCallback:^(FullBuffer* buffer) { [self whatever]; }]; …}
Here the API does not make much sense, but it would make sense when communicating with a superclass, for example. We retain the buffer handler, the buffer handler retains us. Compare with something like this:
typedef void (^Callback)(void);@interface VideoEncoder : NSObject {…}- (void) encodeVideoAndCall: (Callback) block;@end@interface Foo : NSObject {…}@property(retain) VideoEncoder *encoder;@end@implementation Foo- (void) somewhere { [encoder encodeVideoAndCall:^{ [self doSomething]; }];}
In these situations I don’t do the self
aliasing. You do get a retain cycle, but the operation is short-lived and the block will get out of memory eventually, breaking the cycle. But my experience with blocks is very small and it might be that self
aliasing comes out as a best practice in the long run.