為什麼要優化NSDateFormatter?
首先,過度的建立NSDateFormatter
用於NSDate
與NSString
之間轉換,會導致App卡頓,開啟Profile工具查一下效能,你會發現這種操作佔CPU比例是非常高的。據官方說法,建立NSDateFormatter
代價是比較高的,如果你使用的非常頻繁,那麼建議你快取起來,快取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
優化方式有哪些?
a.延遲轉換
即只有在UI
需要使用轉換結果時在進行轉換。
b.Cache in Memory
根據NSDateFormatter
執行緒安全性,不同的iOS系統版本記憶體快取如下:
- prior to iOS 7
如果直接採用靜態變數進行儲存,那麼可能就會存線上程安全問題,在iOS 7之前,NSDateFormatter
是非執行緒安全的,因此可能就會有兩條或以上的執行緒同時訪問同一個日期格式化物件,從而導致App崩潰。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
+ (NSDateFormatter *)cachedDateFormatter { NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary]; NSDateFormatter *dateFormatter = [threadDictionary objectForKey:@"cachedDateFormatter"]; if (!dateFormatter) { dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setLocale:[NSLocale currentLocale]]; [dateFormatter setDateFormat: @"YYYY-MM-dd HH:mm:ss"]; [threadDictionary setObject:dateFormatter forKey:@"cachedDateFormatter"]; } return dateFormatter; } |
- iOS 7 or later
在iOS 7、macOS 10.9及以上系統版本,NSDateFormatter
都是執行緒安全
的,因此我們無需擔心日期格式化物件在使用過程中被另外一條執行緒給修改,為了提高效能,我們還可以在上述程式碼塊中進行簡化(除去冗餘部分)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static NSDateFormatter *cachedDateFormatter = nil; + (NSDateFormatter *)cachedDateFormatter { // If the date formatters aren't already set up, create them and cache them for reuse. if (!dateFormatter) { dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setLocale:[NSLocale currentLocale]]; [dateFormatter setDateFormat: @"YYYY-MM-dd HH:mm:ss"]; } return dateFormatter; } |
如果快取了日期格式化或者是其他依賴於current locale
的物件,那麼我們應該監聽NSCurrentLocaleDidChangeNotification
通知,當current locale
變化時及時更新被快取的日期格式化物件。
In theory you could use an auto-updating locale (autoupdatingCurrentLocale) to create a locale that automatically accounts for changes in the user’s locale settings. In practice this currently does not work with date formatters.
Apple Threading Programming Guide
c.利用標準C語言庫
如果時間日期格式是固定的,我們可以採用C語言中的strptime函式,這樣更加簡單高效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
- (NSDate *) easyDateFormatter{ time_t t; struct tm tm; char *iso8601 = "2016-09-18"; strptime(iso8601, "%Y-%m-%d", &tm); tm.tm_isdst = -1; tm.tm_hour = 0;//當tm結構體中的tm.tm_hour為負數,會導致mktime(&tm)計算錯誤 /** //NSString *iso8601String = @"2016-09-18T17:30:08+08:00"; //%Y-%m-%d [iso8601String cStringUsingEncoding:NSUTF8StringEncoding] { tm_sec = 0 tm_min = 0 tm_hour = 0 tm_mday = 18 tm_mon = 9 tm_year = 116 tm_wday = 2 tm_yday = 291 tm_isdst = 0 tm_gmtoff = 28800 tm_zone = 0x00007fd9b600c31c "CST" } ISO8601時間格式:2004-05-03T17:30:08+08:00 參考Wikipedia */ t = mktime(&tm); //http://pubs.opengroup.org/onlinepubs/9699919799/functions/mktime.html //secondsFromGMT: The current difference in seconds between the receiver and Greenwich Mean Time. return [NSDate dateWithTimeIntervalSince1970:t + [[NSTimeZone localTimeZone] secondsFromGMT]]; } |
相關資料: