昨天被标题的bug搞了一上午,总算在一位大佬的指点下顺利解决问题。
首先贴一下我是怎么出现在这个bug的
我想根据请求服务器后台返回的未读消息数量,动态设置底部分栏控制器的角标
于是就有了下面的代码
运行的时候报错 unrecognized selector sent to instance 0xxxxxxxxxxx
一开始我以为这里面不能用self
后来经过大佬的分析
应该是返回的数据引用有问题
数据类型不对
服务器返回的是json,如下
{"status":1,"num":1}
我这里用 NSJSONSerialization解析json数据
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
解析出来的数据是字符串,但是!!!
字符串也分长(long)短型,还有什么无符型等等,我贴一个网上的说明
所以,我使用dict[@"status"]和dict[@"num"]时都要转成正常的string或者integer
所以最后我的代码就变成这样
__weak __typeof(&*self)weakSelf = self;
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//NSLog(@"返回结果%@",response);
if (error == nil) {
//6.解析服务器返回的数据
//说明:(此处返回的数据是JSON格式的,因此使用NSJSONSerialization进行反序列化处理)
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSString * num = dict[@"num"];
if([dict[@"status"] integerValue] >0){
NSLog(@"判断生效");
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.navigationController.tabBarItem.badgeValue = dict[@"num"];
}
}else{
NSLog(@"推送错误:%@",error.userInfo);
}
}];
解释一下里面涉及的三个注意点:
现通过[dict[@"status"] integerValue] 将dict[@"status"]转成int类型作为判断条件。
dispatch_async(dispatch_get_main_queue(), ^{}这个方法是返回主线程设置角标,如果不返回主线程就会在控制台发出警告([Animation] +[UIView setAnimationsEnabled:] being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior.),但是程序并不会崩溃。
这里为什么会用到 __weak __typeof(&*self)weakSelf = self;呢 。我们在datatask(block中)直接使用self是不可取的。因为block会copy它内部的变量,可能会造成引用循环,使用__weak性质的self替代self,可以切断block对self的引用,避免循环引用。typeof(self) 是获取到self的类型,这样定义出的weakSelf就是和self一个类型的, 加上__weak是建立一个若引用,整句就是给self定义了一个若引用性质的替身;
至于你如果遇到这样情况,可参考一下,先将json数据format,无论是否一开始对不对,还是建议先转一下。其次不要直接使用self。用弱引用。