今天 Bugly 上发现一个 NSDateFormatter 相关的崩溃,有其奇怪。
问题点
定位
解决:通过加锁的方式可以规避这个问题
+ (NSDateFormatter *)dateFormatterWithFormat:(NSString * _Nullable)format {
// NSDateFormatter 是不安全的, 此处通过当前线程缓存加锁的方式解决异常 Bugly Crash
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
NSString *key = [NSString stringWithFormat:@"%@%@",kLLDateToolFormatterIden,format];
NSDateFormatter *dateFormatter = threadDictionary[key];
if(!dateFormatter) {
@synchronized(self) {
if(!dateFormatter) {
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = format ? format : kLLDateDefaultFormat;
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-Hans_CN"];
threadDictionary[key] = dateFormatter;
}
}
}
return dateFormatter;
}
疑惑和反思
- dispatch_once 内为啥还会发生同时读写, dispatch_once 内在进程中只会读写一次的
- NSDateFormatter 在 iOS 7.0 后已经是安全的类啦
static NSDateFormatter *dateFormatter = nil;
+ (NSString *)timestampStringFromRequestDate:(NSDate *)date {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"HH:mm:ss";
});
return [dateFormatter stringFromDate:date];
}
所以猜测,原本代码中可能是不是 静态变量 Formatter 在外面被意外接触到,而影响到他被干掉了,从而此处被影响到了,所以更改下:
+ (NSString *)timestampStringFromRequestDate:(NSDate *)date {
static NSDateFormatter *dateFormatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"HH:mm:ss";
});
return [dateFormatter stringFromDate:date];
}
所以,除了加锁外,暂时也可以这样处理的,感觉对两个疑惑更合理的。
网友评论