block的实现思想是通过建立局部变量的快照,让block中的修改不影响原始变量。在实现方式上为了能够延迟执行某个block,需要hold住相关的变量,内部会retain变量。比方说含有copy属性的block在使用_instanceObj时不会retain变量,但是会retain self,如果使用不当就会导致循环引用。
无需解决循环引用的闭包
可以直接使用self或者_instanceObj
不持有block
[UIView animateWithDuration:0.2 animations:^{
self.alpha = 0.0f;
} completion:^(BOOL finished) {
[self stopLoading];
}];
同步执行
[_messageList enumerateObjectsUsingBlock:^(TimelineMessageData *nodeData, NSUInteger index, BOOL *stop) {
if (nodeData.svrID == msgData.svrID) {
[_tableView reloadRow:index inSection:kSectionOffset rowAnimation:UITableViewRowAnimationNone];
*stop = YES;
}
}];
需要解决循环引用的闭包
不可以直接使用self或者_instanceObj,需要做些额外的工作,常用的处理方式有两种
使用weakSelf+strongSelf
直接调用一个实例变量,会被编译器处理成 ‘self->theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomething];
});
在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomething];
[weakSelf doOtherThing];
});
__strong 确保在 Block 内,strongSelf 不会被释放。
__weak __typeof__(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong __typeof(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doOtherThing];
});
主动断开循环引用
在如下两个block中可直接用self。
- (void)startWithCompletionBlockWithSuccess:(void (^)(YTKBatchRequest *batchRequest))success
failure:(void (^)(YTKBatchRequest *batchRequest))failure;
- (void)setCompletionBlockWithSuccess:(void (^)(YTKBatchRequest *batchRequest))success
failure:(void (^)(YTKBatchRequest *batchRequest))failure;
因为在回调函数中主动断开了循环引用。
- (void)handleRequestResult:(AFHTTPRequestOperation *)operation {
NSString *key = [self requestHashKey:operation];
YTKBaseRequest *request = _requestsRecord[key];
YTKLog(@"Finished Request: %@", NSStringFromClass([request class]));
if (request) {
BOOL succeed = [self checkResult:request];
if (succeed) {
[request toggleAccessoriesWillStopCallBack];
[request requestCompleteFilter];
if (request.delegate != nil) {
[request.delegate requestFinished:request];
}
if (request.successCompletionBlock) {
request.successCompletionBlock(request);
}
[request toggleAccessoriesDidStopCallBack];
} else {
YTKLog(@"Request %@ failed, status code = %ld",
NSStringFromClass([request class]), (long)request.responseStatusCode);
[request toggleAccessoriesWillStopCallBack];
[request requestFailedFilter];
if (request.delegate != nil) {
[request.delegate requestFailed:request];
}
if (request.failureCompletionBlock) {
request.failureCompletionBlock(request);
}
[request toggleAccessoriesDidStopCallBack];
}
}
[self removeOperation:operation];
[request clearCompletionBlock];
}
- (void)cancelRequest:(YTKBaseRequest *)request {
[request.requestOperation cancel];
[self removeOperation:request.requestOperation];
[request clearCompletionBlock];
}
- (void)clearCompletionBlock {
self.successCompletionBlock = nil;
self.failureCompletionBlock = nil;
}