我对Objective-C中的块用法有点困惑。我目前使用ARC,我有相当多的块在我的应用程序,目前总是引用自我,而不是它的弱引用。这可能是这些块保留自我并阻止它被释放的原因吗?问题是,我应该总是在块中使用self的弱引用吗?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
进程操作.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
As Leo points out, the code you added to your question would not suggest a strong reference cycle (a.k.a., retain cycle). One operation-related issue that could cause a strong reference cycle would be if the operation is not getting released. While your code snippet suggests that you have not defined your operation to be concurrent, but if you have, it wouldn't be released if you never posted isFinished, or if you had circular dependencies, or something like that. And if the operation isn't released, the view controller wouldn't be released either. I would suggest adding a breakpoint or NSLog in your operation's dealloc method and confirm that's getting called.
你说:
我理解保留周期的概念,但我不太确定在块中会发生什么,所以这让我有点困惑
The retain cycle (strong reference cycle) issues that occur with blocks are just like the retain cycle issues you're familiar with. A block will maintain strong references to any objects that appear within the block, and it will not release those strong references until the block itself is released. Thus, if block references self, or even just references an instance variable of self, that will maintain strong reference to self, that is not resolved until the block is released (or in this case, until the NSOperation subclass is released.
有关更多信息,请参见“使用Objective-C编程:使用块”文档中的“在捕获自我时避免强引用循环”部分。
如果你的视图控制器仍然没有被释放,你只需要确定未解决的强引用驻留在哪里(假设你确认NSOperation正在被释放)。一个常见的例子是使用重复的NSTimer。或错误地维护强引用的某个自定义委托或其他对象。你可以经常使用工具来追踪对象在哪里获得它们的强引用,例如:
或者在Xcode 5中:
As Leo points out, the code you added to your question would not suggest a strong reference cycle (a.k.a., retain cycle). One operation-related issue that could cause a strong reference cycle would be if the operation is not getting released. While your code snippet suggests that you have not defined your operation to be concurrent, but if you have, it wouldn't be released if you never posted isFinished, or if you had circular dependencies, or something like that. And if the operation isn't released, the view controller wouldn't be released either. I would suggest adding a breakpoint or NSLog in your operation's dealloc method and confirm that's getting called.
你说:
我理解保留周期的概念,但我不太确定在块中会发生什么,所以这让我有点困惑
The retain cycle (strong reference cycle) issues that occur with blocks are just like the retain cycle issues you're familiar with. A block will maintain strong references to any objects that appear within the block, and it will not release those strong references until the block itself is released. Thus, if block references self, or even just references an instance variable of self, that will maintain strong reference to self, that is not resolved until the block is released (or in this case, until the NSOperation subclass is released.
有关更多信息,请参见“使用Objective-C编程:使用块”文档中的“在捕获自我时避免强引用循环”部分。
如果你的视图控制器仍然没有被释放,你只需要确定未解决的强引用驻留在哪里(假设你确认NSOperation正在被释放)。一个常见的例子是使用重复的NSTimer。或错误地维护强引用的某个自定义委托或其他对象。你可以经常使用工具来追踪对象在哪里获得它们的强引用,例如:
或者在Xcode 5中:
我完全同意@jemmons的观点:
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];
}];
为了克服这个问题,可以在块内的weakSelf上定义一个强引用:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
MyObject *strongSelf = weakSelf;
[strongSelf doSomething];
}];