项目中遇到一个偶现crash,如图:
按道理-[__NSDictionaryM objectForKey:] 即便dict是nil或者key是nil都不会crash啊。
查阅资料:有同学反馈 NSMutableDictionary is not thread safe。先在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];
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];
}
将这个代码放到demo中。必现crash。比较有意思的是:循环10000次才必现一次crash。
Stack Overflow网友上说的,在+ (NSString *)openUDID方法中操作dict的地方添加@synchronized (self){ },但是在这个case里并不好使
分析后发现:后台线程和主线程都只对dict进行操作了。并不是对openUDID方法操作。所以需要对 [self cacheDictionary]进行copy操作。
特此记录一下。