发布另一个答案,因为这对我来说也是一个问题。我最初认为我必须在块内有自引用的任何地方使用 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];
}
在第二种情况下,您不需要 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;
}