项目发http请求,现在一般的都是用的第三方开源库,当然发异步请求时我们也会写几个回调函数来进行请求返回时的处理。不过前段时间看一个朋友写的代码,里面很用block简单的实现了回调相关的部分。比如:
01 | self.request=[ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]]; |
02 | [_request setRequestMethod:@ "GET" ]; |
04 | [_request setCompletionBlock:^{ |
06 | _mobileField.enabled= YES; |
07 | _nextStepBtn.enabled = YES; |
08 | NSInteger statusCode = [_request responseStatusCode]; |
09 | NSString *result = [_request responseString]; |
看后感觉非常的方便与简单,但是使用Instruments跑的时候老是有内存泄漏的问题。后来查找一翻,I find out the reason;
原来block中调用了self或者self的成员变量,block就retain了self,而self也retain block,所以self和block都无法释放,最终形成cycle。
正确的写法如下:
01 | self.request=[ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]]; |
02 | [_request setRequestMethod:@ "GET" ]; |
03 | __unsafe_unretained ASIHTTPRequest *_requestCopy = _request; |
04 | __unsafe_unretained RegistUserViewController *this = self; |
05 | [_request setCompletionBlock:^{ |
07 | this.mobileField.enabled= YES; |
08 | this.nextStepBtn.enabled = YES; |
09 | NSInteger statusCode = [_requestCopy responseStatusCode]; |
10 | NSString *result = [_requestCopy responseString]; |
注意其中的__unsafe_unretained关键词,这个就是让block对所修饰的变量使用弱引用,也就ARC中的__weak。这样修饰的变量就不会被retain。
还有一种是用__block关键词的写法,也是官方文档中的写法(http://allseeing-i.com/ASIHTTPRequest/How-to-use);
01 | - (IBAction)grabURLInBackground:(id)sender |
04 | __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; |
05 | [request setCompletionBlock:^{ |
07 | NSString *responseString = [request responseString]; |
10 | NSData *responseData = [request responseData]; |
12 | [request setFailedBlock:^{ |
13 | NSError *error = [request error]; |
15 | [request startAsynchronous]; |
还有一种将self改成弱引用的写法是
__block typeof(self) bself = self;
关于block中的成员变量的调用方法也要注意下面两点:
对于property就用点操作符 bself.xxx
对于非property的成员变量就用->操作符 bself->xxx
最后总结,所有的这些都是围绕一点,block会retain相应的变量,我们要使用用弱引用修饰的变量。