iOS陷阱--NSDateFormatter的线程安全性

apple官网文档:

Thread Safety

On iOS 7 and later NSDateFormatter is thread safe.

In macOS 10.9 and later NSDateFormatter is thread safe so long as you are using the modern behavior in a 64-bit app.

On earlier versions of the operating system, or when using the legacy formatter behavior or running in 32-bit in macOS, NSDateFormatter is not thread safe, and you therefore must not mutate a date formatter simultaneously from multiple threads.


说明:ios7及以上版本 NSDateFormatter是线程安全的!之前的版本确定不是线程安全的!所以以后不要管它的线程安全问题了!


========================================================转载=====================================================================

经常需要将NSDate和NSString进行互转,一般我们会这么写:

  1. NSDate转NSString
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@”yyyy-MM-dd’T’HH:mm:ss”];

    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@”Asia/Shanghai”]];
    return [dateFormatter dateFromString:dateString];
  2. NSString转NSDate
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSTimeZone *timeZone = [NSTimeZone defaultTimeZone];
    [dateFormatter setTimeZone:timeZone];
    [dateFormatter setDateFormat:@”yyyy-MM-dd HH:mm:ss Z”];
    return [dateFormatter stringFromDate:date];
    上面运行起来好像很顺畅,可是有一天,老大跑过来问:“hey,小张,有用户反应我们的App滑动很卡啊”。于是你打开Profile工具查了一下性能,你会发现上述两个转换函数占CPU比例非常高。怎么优化呢?
  1. 延迟转换并Cache
    即只有在UI需要使用转换结果时再执行转换,并将结果缓存起来。
  2. NSDateFormatter对象只生成1次
   方法1很好容易实现, 下面我们实现方法2:
static NSDateFormatter *dateFormatter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    dateFormatter = [[NSDateFormatter alloc] init];
});
[dateFormatter setDateFormat:@”yyyy-MM-dd’T’HH:mm:ss”];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@”Asia/Shanghai”]];
return [dateFormatter dateFromString:dateString];

    貌似也挺容易的,哈哈经过上面的改造后,你会发现性能得到了显著提升,非常高兴的给老大发布新版本,很快老大又过来把你劈头盖脸地训了一顿:“怎么老是Crash,这么不稳定?赶紧fix”。
    一查CrashReport,发现在[dateFormatter dateFromString:dateString]这里出了问题。这就奇怪了?系统函数库也有bug么?
    当然不是了,这是因为 NSDateFormatter不是线程安全的 ,请查看 https://developer.apple.com/library/mac/documentation/cocoa/conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html ,里面列出了线程安全和不安全的类。当多个线程同时访问1个NSDateFormatter对象时,有可能会Crash。
那怎么办?不要泄气,咱们给每个线程准备1个NSDateFormatter,大家就不会打得头破血流了。
解决方案:
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
NSDateFormatter *dateFormatter = threadDictionary[@”mydateformatter”];

if(!dateFormatter){
    @synchronized(self){
        if(!dateFormatter){
            dateFormatter = [[NSDateFormatter alloc] init];
           [dateFormatter setDateFormat:@”yyyy-MM-dd HH:mm:ss”];
           [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@”Asia/Shanghai”]];
          threadDictionary[@”mydateformatter”] = dateFormatter;
         }
    }
}
发现没有,上面使用了 double-check 技术哦,哈哈,这里千万不要再用dispatch_once哈。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值