最近做项目用到了ASI发送网络请求。遇到这么个情况之前没遇到过的,就是发送一个网络请求,需要用到请求回来的响应数据显示在tableview上面,代码是这么写的
__weak ASIHTTPRequest * formlogin=[ASIHTTPRequest requestWithURL:url];
formlogin.timeOutSeconds=60;
formlogin.delegate=self;
[formlogin setCompletionBlock:^{
NSString * fanhui=[formlogin responseString];
NSMutableDictionary * dic= [self dictionaryWithJsonString:fanhui];
// NSLog(@"**********%@",dic);
NSDictionary * response=[[NSDictionary alloc]init];
NSArray * dataArr=[[NSArray alloc]init];
response=[dic objectForKey:@"response"];
NSString * code=[NSString stringWithFormat:@"%@",[response objectForKey:@"code"]];
if ([code isEqualToString:@"0"]) {
dataArr=[dic objectForKey:@"data"];
LinenumberViewController * ltvc = [[LinenumberViewController alloc]init];
if (dataArr != nil) {
ltvc.dataArr=dataArr;
__weak AddCardViewController * weak=self;
ltvc.changeBlock1=^(NSString * bankcode,NSString * bankname){
weak.linenumberLab.text=bankname;
weak.branchName=bankname;
weak.branchId=bankcode;
} ;
[self.navigationController pushViewController:ltvc animated:YES];
}
else{
NSLog(@"城市数组和城市编码数组为空了");
}
}
}];
[request1 setFailedBlock:^{
NSLog(@"hehe");
}];
[request1 startAsynchronous];
注意上面的网络请求的ASIhttpRequest实例化为formlogin对象,下面用到了block方法,因为怕引起循环引用,所以实例化时前面加了__weak,这样做在测试时是没有问题的,可是项目发布之后该方法的setcomplete回调是不起作用的,究其原因,查了一下相关资料,贴在下面:http://blog.csdn.net/fengsh998/article/details/38090205
大体的意思就是,在实例化时不加__weak其实在ARC中会产生(Capturing 'demo' strongly in this block is likely to lead to a retain cycle)告警。为了消除这个警告加上__weak,说这是一个WEAK变量,就马上会被release。因此就不会执行block中的内容。
那么怎么去除掉这种危险呢?有几种解决办法:(当然是针对这种情况而非此项目):
ASIHTTPRequest * formlogin=[ASIHTTPRequest requestWithURL:url];
formlogin.timeOutSeconds=60;
formlogin.delegate=self;
__weak ASIHTTPRequest * request1=formlogin;
[request1 setCompletionBlock:^{
NSString * fanhui=[request1 responseString];
NSMutableDictionary * dic= [self dictionaryWithJsonString:fanhui];
// NSLog(@"**********%@",dic);
NSDictionary * response=[[NSDictionary alloc]init];
NSArray * dataArr=[[NSArray alloc]init];
response=[dic objectForKey:@"response"];
NSString * code=[NSString stringWithFormat:@"%@",[response objectForKey:@"code"]];
if ([code isEqualToString:@"0"]) {
dataArr=[dic objectForKey:@"data"];
LinenumberViewController * ltvc = [[LinenumberViewController alloc]init];
if (dataArr != nil) {
ltvc.dataArr=dataArr;
__weak AddCardViewController * weak=self;
ltvc.changeBlock1=^(NSString * bankcode,NSString * bankname){
weak.linenumberLab.text=bankname;
weak.branchName=bankname;
weak.branchId=bankcode;
} ;
[self.navigationController pushViewController:ltvc animated:YES];
}
else{
NSLog(@"城市数组和城市编码数组为空了");
}
}
}];
[request1 setFailedBlock:^{
NSLog(@"hehe");
}];
[request1 startAsynchronous];
在上面的实例化时,不加_-weak,在下面块将引入时,用__weak的实例来引入,带入到block中,这样就可以了因此,写这个主要用来告戒一些喜欢用BLOCK但又想当然的朋友,有一些朋友喜欢去除告警,但只是盲目的加上__weak 或__block关键语,往往可能存在一些重大的安全隐患。就像演示中block根本不走。如果到了发布时,为了去告警而这样简单的处理了,并没有进行测试就打包。哪么将死得很惨。。。。。
好,到了尾声,来说说为什么朋友问我block会不会引行死循环,我说不会的理由。
见码:
- - (IBAction)onTest:(id)sender
- {
- BlockDemo *demo = [BlockDemo blockdemo];//[[BlockDemo alloc]init];
- [demo setExecuteFinishedParam:^(BlockDemo * ademo) {
- if (ademo.resultCode == 200) {
- NSLog(@"call back ok.");
- }
- }];
- [demo executeTest];
- }
不管是在外面init,还是在里面,且没有加__block 及__weak。为什么,因为我个人常常在使用自己写的block时,如果是回调,比较喜欢把自身当作参数传到block中。这样期实是编译器给我们做了弱引用。因此不会产生循环引用。
最后,针对此情况,在此项目中,我找到了三种解决办法,上面的是第一种解决办法,第二章则是用ASI的代理方法
ASIHTTPRequest * request0=[ASIHTTPRequest requestWithURL:url];
NSLog(@"1");
request0.timeOutSeconds=60;
NSLog(@"2");
request0.delegate=self;
NSLog(@"3");
mudata=[[NSMutableData alloc]init];
[request0 startAsynchronous];
这个是实例化网络请求发送请求,在回调处处理返回的数据,而不是在本方法中处理。具体请查看代理方法,在此略过。第三种方法:不使用ASIhttprequest,而是使用ASIformdatarequest。
ASIFormDataRequest * formlogin=[ASIFormDataRequest requestWithURL:url];
// formlogin.timeOutSeconds=60;
// formlogin.delegate=self;
// __weak ASIFormDataRequest * request1=formlogin;
// [request1 setCompletionBlock:^{
//
// NSLog(@"呵呵");
// NSString * fanhui=[request1 responseString];
// NSMutableDictionary * dic= [self dictionaryWithJsonString:fanhui];
// // NSLog(@"**********%@",dic);
// NSDictionary * response=[[NSDictionary alloc]init];
// NSArray * dataArr=[[NSArray alloc]init];
// response=[dic objectForKey:@"response"];
// NSString * code=[NSString stringWithFormat:@"%@",[response objectForKey:@"code"]];
// if ([code isEqualToString:@"0"]) {
// dataArr=[dic objectForKey:@"data"];
//
// LinenumberViewController * ltvc = [[LinenumberViewController alloc]init];
// if (dataArr != nil) {
// ltvc.dataArr=dataArr;
//
// __weak AddCardViewController * weak=self;
// ltvc.changeBlock1=^(NSString * bankcode,NSString * bankname){
// weak.linenumberLab.text=bankname;
// weak.branchName=bankname;
// weak.branchId=bankcode;
// } ;
// [self.navigationController pushViewController:ltvc animated:YES];
// }
// else{
// NSLog(@"城市数组和城市编码数组为空了");
// }
// }
// }];
// [request1 setFailedBlock:^{
// NSLog(@"hehe");
// }];
//
// [request1 startAsynchronous];
这样也可以的,有的地方有朋友可能不懂事干嘛的,我这个是从后台请求回来的银行列表数据,和对应的银行编码code。使之按条件搜索显示在tableview上,大体就是这样了。