これは私にとっても問題だったので、別の回答を投稿してください。私は当初、ブロック内に自己参照がある場合はどこでも blockSelf を使用する必要があると考えていました。これは当てはまりません。オブジェクト自体にブロックがある場合のみです。実際、これらの場合に blockSelf を使用すると、ブロックから結果が返される前にオブジェクトが解放される可能性があり、それを呼び出そうとするとクラッシュするため、明らかに応答まで self を保持する必要があります戻ってくる。
最初のケースは、ブロック内で参照されているブロックが含まれているため、保持サイクルがいつ発生するかを示しています。
#import <Foundation/Foundation.h>
typedef void (^MyBlock)(void);
@interface ContainsBlock : NSObject
@property (nonatomic, copy) MyBlock block;
- (void)callblock;
@end
@implementation ContainsBlock
@synthesize block = _block;
- (id)init {
if ((self = [super init])) {
//__block ContainsBlock *blockSelf = self; // to fix use this.
self.block = ^{
NSLog(@"object is %@", self); // self retain cycle
};
}
return self;
}
- (void)dealloc {
self.block = nil;
NSLog (@"ContainsBlock"); // never called.
[super dealloc];
}
- (void)callblock {
self.block();
}
@end
int main() {
ContainsBlock *leaks = [[ContainsBlock alloc] init];
[leaks callblock];
[leaks release];
}
2 番目のケースでは blockSelf は必要ありません。これは、呼び出し元のオブジェクトに、self を参照するときに保持サイクルを引き起こすブロックが含まれていないためです。
#import <Foundation/Foundation.h>
typedef void (^MyBlock)(void);
@interface BlockCallingObject : NSObject
@property (copy, nonatomic) MyBlock block;
@end
@implementation BlockCallingObject
@synthesize block = _block;
- (void)dealloc {
self.block = nil;
NSLog(@"BlockCallingObject dealloc");
[super dealloc];
}
- (void)callblock {
self.block();
}
@end
@interface ObjectCallingBlockCallingObject : NSObject
@end
@implementation ObjectCallingBlockCallingObject
- (void)doneblock {
NSLog(@"block call complete");
}
- (void)dealloc {
NSLog(@"ObjectCallingBlockCallingObject dealloc");
[super dealloc];
}
- (id)init {
if ((self = [super init])) {
BlockCallingObject *myobj = [[BlockCallingObject alloc] init];
myobj.block = ^() {
[self doneblock]; // block in different object than this object, no retain cycle
};
[myobj callblock];
[myobj release];
}
return self;
}
@end
int main() {
ObjectCallingBlockCallingObject *myObj = [[ObjectCallingBlockCallingObject alloc] init];
[myObj release];
return 0;
}