Kiedy coś takiego nazywa się drogim, nie musi to oznaczać, że nigdy nie powinno się tego robić, oznacza to po prostu unikanie tego w sytuacjach, w których trzeba jak najszybciej wyjść z metody. Na przykład, kiedy iPhone 3G był najnowszym urządzeniem, pisałem aplikację z UITableView
, która formatowała liczby do wyświetlenia w każdej komórce (mogę dodać, że to było z powrotem, gdy byłem początkującym w rozwoju iOS). Moja pierwsza próba była następująca:
- (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;
}
Przewijanie wydajność tego kodu był straszne. Szybkość klatek spadła do około 15 klatek na sekundę, ponieważ przydzielałem nowe NSNumberFormatter
za każdym razem, gdy zostało uderzone tableView:cellForRowAtIndexPath:
.
Naprawiłem go przez zmianę kodu do tego:
- (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;
}
Różnica polega na tym, że ja leniwie załadował NSNumberFormatter
się z ivar, tak, że każdy bieg tableView:cellForRowAtIndexPath:
nie przydziela nową instancję. Ta prosta zmiana przesunęła wydajność przewijania z powrotem do około 60 FPS.
Ten konkretny przykład nie jest już tak istotny, ponieważ nowsze układy są w stanie obsłużyć przydział bez wpływu na wydajność przewijania, ale zawsze lepiej być tak wydajnym, jak to tylko możliwe.
profilowanie jest bezbolesny – justin
Można profil swoją aplikację, aby określić, w jaki sposób lepiej odpowiada Twoim potrzebom. Sądzę, że programiści chcieli zwrócić uwagę, że coś tak nieszkodliwego brzmiącego jak "NSDateFormatter" może mieć dość skomplikowany kod inicjalizatora, więc oto podpowiedź w dokumentacji, aby jak najwięcej użyć zainicjowanego obiektu. –