2012-01-12 78 views
40

當人們認爲這很貴時,他們的意思是什麼?我爲中間存儲創建了很多瞬態對象的實例(NSString和NSDate是典型的)。我如何知道我的程序使用NSDateFormatter是否過度使用它?直到現在,我傾向於創建相當於單身人士的東西,但是我的偏好是將其封裝到與它相關的一些其他對象中,所以我可以使用自引用。爲什麼分配或初始化NSDateFormatter被視爲「昂貴」?

缺少運行性能測試,我正在尋找更好的「經驗法則」理解爲什麼我應該或不應該這樣做。

+0

分析是無痛 – justin 2012-02-04 14:11:00

+0

您可以分析您的應用程序,以確定哪種方式適合您的需要更好。我認爲開發人員想指出,像NSDateFormatter這樣無害的東西可能有一些非常複雜的初始化代碼,所以這裏提供了一個文檔中的提示,以便儘可能重用初始化對象。 – 2012-02-06 15:19:02

回答

33

當像這樣的東西被稱爲昂貴的,並不一定意味着你永遠不應該這樣做,這只是意味着避免在需要儘快擺脫方法的情況下做到這一點。例如,當iPhone 3G是最新的設備時,我正在編寫一個帶有格式化數字的應用程序,用於在每個單元格中顯示(我可能會補充說,當我是iOS開發人員的初學者時,這已經回來了)。我的第一次嘗試以下操作:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    NSString *reuseIdentifier = @"cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath]; 

    MyManagedObject *managedObject = [self.managedObjects objectAtIndex:indexPath.row]; 
    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; 
    [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 

    [cell.textLabel setText:[managedObject title]]; 
    [cell.detailTextLabel setText:[numberFormatter stringFromNumber:[managedObject amount]]]; 

    return cell; 
} 

這段代碼的滾動性能可怕。由於我每次撥打tableView:cellForRowAtIndexPath:時都會分配一個新的NSNumberFormatter,因此幀速率降至大約15 FPS。

我固定它的代碼更改爲此:

- (NSNumberFormatter *)numberFormatter { 

    if (_numberFormatter != nil) { 
     return _numberFormatter; 
    } 

    _numberFormatter = [[NSNumberFormatter alloc] init]; 
    [_numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 

    return _numberFormatter; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    NSString *reuseIdentifier = @"cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath]; 

    MyManagedObject *managedObject = [self.managedObjects objectAtIndex:indexPath.row]; 
    NSNumberFormatter *numberFormatter = [self numberFormatter]; 

    [cell.textLabel setText:[managedObject title]]; 
    [cell.detailTextLabel setText:[numberFormatter stringFromNumber:[managedObject amount]]]; 

    return cell; 
} 

這裏的區別是,我懶洋洋地加載到NSNumberFormatter伊娃,使tableView:cellForRowAtIndexPath:每次運行不再分配一個新的實例。這個簡單的改變將滾動性能提高到大約60 FPS。

這個具體的例子不再那麼重要,因爲新芯片能夠處理分配而不影響滾動性能,但總是儘可能高效。

+1

與此相關的危險是您必須確保您的numberFormatter不會從多個線程中調用。它不支持併發。 – 2013-09-13 22:13:33

+1

@GregMaletic這是一個非常簡單的例子,''''tableView:cellForRowAtIndexPath:''''將永遠不會被除了主線程以外的任何東西調用。 – 2013-09-14 22:12:09

+0

@Eli True,但是如果在代碼中的另一個方法中調用numberFormatter方法,並且該方法在另一個線程上調用,那麼可以使用自己的方法。你只需要記住只從主線程調用你的numberFormatter方法。 – 2013-09-15 02:04:13

7

我以前有過同樣的問題。我在一些我正在使用的應用程序上運行過Instruments,我發現以前的開發人員正在爲他們所做的每個自定義日誌創建一個新的NSDateFormatter。由於每個屏幕他們用來記錄約3條線。該應用程序只用了大約1秒鐘才創建NSDateFormatters。

簡單的解決方案是將日期格式化程序實例作爲屬性保留在您的類中,然後將其重用於每個日誌行。

經過一些微不足道的想法之後,我帶着一個「工廠」來處理NSDateFormatters的重用,它基於想要的格式和語言環境。我請求某種格式和語言環境的日期格式化程序,我的課程將已經加載的格式化程序給我。良好的性能調整,你應該嘗試。

PS:也許有人想對它進行測試,所以我把它公開:https://github.com/DougFischer/DFDateFormatterFactory/blob/master/README.md

+1

你有沒有得到任何反饋? – Dejell 2013-09-17 16:29:36

+1

反饋:作品像一個魅力 – Laszlo 2013-10-15 09:30:34

+1

我同意。簡單方便。我目前的應用程序使用它有很多好處。非常感謝 – rmvz3 2014-07-29 02:47:24