iOS之NSDateFormatter 性能瓶颈

本文介绍NSDateFormatter的性能瓶颈,以及如何解决性能问题。

分别用NSDateFormatter和 C 的localtime()方法将时间转化成一个可读的字符串,转化1024 * 10次,然后对比一下消耗的时间

static NSUInteger totalTimes = 1024 * 10;

@interface ViewController ()
@property (nonatomic, strong) NSString *dateAsString;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self converDateToStringUsingDateFormatter];
    
    [self convertDateToStrUsingCLocaltime];
}

- (void)converDateToStringUsingDateFormatter {
    CFAbsoluteTime then = CFAbsoluteTimeGetCurrent();
    for (NSUInteger i = 0; i < totalTimes; i++) {
        NSDateFormatter *newDateForMatter = [[NSDateFormatter alloc] init];
        [newDateForMatter setDateFormat:@"yyyy-MM-dd"];
        self.dateAsString = [newDateForMatter stringFromDate:[NSDate date]];
    }
    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
    NSLog(@"Convert date to string using NSDateFormatte cost time:%f seconds \n",now - then);
}

- (void)convertDateToStrUsingCLocaltime {
    CFAbsoluteTime then = CFAbsoluteTimeGetCurrent();
    for (NSUInteger i = 0; i < totalTimes; i++) {
        time_t timeInterval = [NSDate date].timeIntervalSince1970;
        struct tm *cTime = localtime(&timeInterval);
        self.dateAsString = [NSString stringWithFormat:@"%d-%02d-%02d", cTime->tm_year + 1900, cTime->tm_mon + 1, cTime->tm_mday];
    }
    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
    NSLog(@"Convert date to string using localtime cost time:%f seconds \n",now - then);
}

运行结果如下:

image.png

通过运行结果我们可以得知,使用NSDateFormatter耗时1.5S,使用localtime耗时0.6S,也就是说NSDateFormatter要比localtime 慢3倍+以上。

使用instruments 跑一下 time profile,对比一下两种方式花费时间对比.

time-profile.png

通过分析可以看到性能差距如此之大

为什么NSDateFormatter这么耗时呢?

苹果官方文档中有提到

“Creating a date formatter is not a cheap operation. If you are likely to use a formatter frequently, it is typically more efficient to cache a single instance than to create and dispose of multiple instances. One approach is to use a static
variable.”

也就是说,创建NSDateFormatter的过程开销很大!建议使用时保持一个单例,而不是每次去重新创建
NSDateFormatter对象。

// 声明一个变量
@property (nonatomic, strong) NSDateFormatter *dateFormatter;

// 懒加载实现
- (NSDateFormatter *)dateFormatter {
    if (!_dateFormatter) {
        _dateFormatter = [[NSDateFormatter alloc] init];
        [_dateFormatter setDateFormat:@"yyyy-MM-dd"];
    }
    return _dateFormatter;
}

// 使用单例转换时间
- (void)converDateToStringUsingSingleDateFormatter {
    CFAbsoluteTime then = CFAbsoluteTimeGetCurrent();
    for (NSUInteger i = 0; i < totalTimes; i++) {
        self.dateAsString = [self.dateFormatter stringFromDate:[NSDate date]];
    }
    CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
    NSLog(@"Convert date to string using Single NSDateFormatte cost time:%f seconds \n",now - then);
}

运行结果对比:

image.png

通过运行结果可以看出,如果使用单例,NSDateFormat 开销和localtime()的开销差不多,甚至会稍快一些。

综上所述,最佳实践是,在工程中添加一个NSDateFormatter的单例对象供全工程使用,需要注意的是,NSDateFormatter在iOS7之后(包括iOS7)才是线程安全的。


本文参考Joey_Xu的NSDateFormatter最佳实践,非常感谢该作者


项目连接地址

你可能感兴趣的:(iOS之NSDateFormatter 性能瓶颈)