本文介绍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最佳实践,非常感谢该作者
网友评论