主线程 -[__NSDictionaryM objectForKey:] SEGV_ACCERR 类型的crash
Posted hherima
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了主线程 -[__NSDictionaryM objectForKey:] SEGV_ACCERR 类型的crash相关的知识,希望对你有一定的参考价值。
项目中遇到一个偶现crash,如图:
按道理-[__NSDictionaryM objectForKey:] 即便dict是nil或者key是nil都不会crash啊。况且还在主线程,测试过程中并没有crash。
查阅资料后:Stack Overflow上有同学反馈 NSMutableDictionary is not thread safe。所以先搞一个demo,在demo中模拟一下场景:
+ (NSMutableDictionary *)cacheDictionary
static NSMutableDictionary *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
instance = [[NSMutableDictionary alloc] init];
);
return instance;
+ (NSString *)openUDID
NSMutableDictionary *dict = [self cacheDictionary];
// NSMutableDictionary *dict = [[self cacheDictionary] copy];//修复后代码
NSString *openUDID = nil;
int i = 0;
while (i<10000)
openUDID = [dict objectForKey:@"kSTAD_OPENUDID_CACHEKEY"];
// NSLog(@"openUDID = %@",openUDID);
i++;
return openUDID;
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.greenColor;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
NSMutableDictionary *dict = nil;
dict = [ViewController cacheDictionary];
int i=0;
while (i<10000)
[dict setObject:@"1" forKey:@"kSTAD_OPENUDID_CACHEKEY"];
[dict removeAllObjects];
[dict setObject:@"2" forKey:@"kSTAD_OPENUDID_CACHEKEY"];
[dict removeAllObjects];
[dict setObject:@"3" forKey:@"kSTAD_OPENUDID_CACHEKEY"];
[dict objectForKey:@"kSTAD_OPENUDID_CACHEKEY"];
[dict removeAllObjects];
[dict setObject:@"4" forKey:@"kSTAD_OPENUDID_CACHEKEY"];
i++;
);
[ViewController openUDID];
上面代码,必现crash。crash信息和bugly上的一样,简直一模一样。
调试时候提示如下信息:
Thread1:EXC_BAD_ACCESS(code=1,address=0x0)
比较有意思的是:循环10000次才必现一次crash,小数据量循环不会crash
Stack Overflow网友上说的,在+ (NSString *)openUDID方法中操作dict的地方添加@synchronized (self) ,但是这个锁,这我这个case里并不好使。
分析后发现:后台线程和主线程都只对dict进行操作了。并不是对openUDID方法操作。所以需要对 [self cacheDictionary]进行copy操作。代码就运营正常了。
特此记录一下。
以上是关于主线程 -[__NSDictionaryM objectForKey:] SEGV_ACCERR 类型的crash的主要内容,如果未能解决你的问题,请参考以下文章
NSDictionaryM setObject:forKey: EXC_BAD_ACCESS 崩溃
Android多线程的四种方式:Handler、AsyncTask、ThreadPoolExector、IntentService