Почему выделение или инициализация NSDateFormatter считается "дорогим"?
Что люди имеют в виду, когда говорят, что это дорого? Я создаю экземпляры большого количества временных объектов только для промежуточного хранения (NSString и NSDate являются типичными). Как я узнаю, что использование моей программы NSDateFormatter переусердствовало?
До сих пор я имел тенденцию создавать то, что составляет единичный объект, но я бы предпочел инкапсулировать его в некоторые другие объекты, с которыми он связан, чтобы я мог использовать собственные ссылки.
За исключением выполнения тестов производительности, я ищу лучшего "практического" понимания того, почему я должен или не должен делать это.
2 ответа
Когда что-то подобное называют дорогостоящим, это не обязательно означает, что вы никогда не должны этого делать, это просто означает, что следует избегать этого в ситуациях, когда вам нужно как можно быстрее выйти из метода. Например, когда iPhone 3G был последним устройством, я писал приложение с UITableView
это отформатированные числа для отображения в каждой ячейке (я мог бы добавить, это было еще тогда, когда я был новичком в разработке 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;
}
Производительность прокрутки этого кода была ужасной. Частота кадров упала примерно до 15 кадров в секунду, потому что я выделял новый NSNumberFormatter
каждый раз tableView:cellForRowAtIndexPath:
мыть его.
Я исправил это, изменив код на это:
- (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.
Этот конкретный пример уже не так актуален, поскольку новые чипы способны обрабатывать распределение, не влияя на производительность прокрутки, но всегда лучше быть настолько эффективным, насколько это возможно.
У меня был тот же вопрос некоторое время назад. Я запустил Instruments в каком-то приложении, над которым работал, и выяснил, что предыдущие разработчики создавали новый NSDateFormatter для каждого пользовательского журнала, который они сделали. Так как для каждого экрана они использовали для входа около 3 строк. Приложение раньше тратило около одной секунды только на создание NSDateFormatters.
Простым решением было бы сохранить экземпляр средства форматирования даты в вашем классе в качестве атрибута или чего-либо еще и повторно использовать его для каждой строки журнала.
После некоторых обыденных размышлений я пришел с "фабрикой" для повторного использования NSDateFormatters на основе требуемого формата и локали. Я запрашиваю форматер даты какого-либо формата и локали, и мой класс дает мне уже загруженный форматер. Хорошая производительность настройки, вы должны попробовать.
PS: Может быть, кто-то хотел бы проверить это, поэтому я сделал его публичным: https://github.com/DougFischer/DFDateFormatterFactory/blob/master/README.md