Почему выделение или инициализация NSDateFormatter считается «дорогим»? - PullRequest
43 голосов
/ 12 января 2012

Что люди имеют в виду, когда говорят, что это дорого?Я создаю экземпляры большого количества временных объектов только для промежуточного хранения (NSString и NSDate являются типичными).Как я узнаю, что использование моей программы NSDateFormatter переусердствовало?

До сих пор я имел тенденцию создавать то, что составляет единичный объект, но я бы предпочел инкапсулировать его в некоторые другие объекты, которыми он является.связано с тем, чтобы я мог использовать собственные ссылки.

За исключением тестов производительности, я ищу лучшее "практическое" понимание того, почему я должен или не должен этого делать.

Ответы [ 2 ]

38 голосов
/ 04 февраля 2012

Когда что-то подобное называют дорогостоящим, это не обязательно означает, что вы никогда не должны этого делать, это просто означает, что следует избегать этого в ситуациях, когда вам нужно как можно быстрее выйти из метода.Например, когда 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 FPS, потому что я каждый раз выделял новый NSNumberFormattertableView: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.

Этот конкретный пример уже не так актуален, так как более новые чипы способны обрабатывать выделение, не влияя на производительность прокрутки, но всегда лучшебыть максимально эффективным.

7 голосов
/ 27 апреля 2013

У меня был тот же вопрос некоторое время назад.Я запустил инструменты в каком-то приложении, над которым я работал, и выяснил, что предыдущие разработчики создавали новый NSDateFormatter для каждого пользовательского журнала, который они сделали.Так как для каждого экрана они использовали для входа около 3 строк.Раньше приложение тратило около одной секунды только на создание NSDateFormatters.

Простым решением было бы сохранить экземпляр средства форматирования даты в вашем классе в качестве атрибута или чего-либо еще и повторно использовать его для каждой строки журнала.

После некоторого тривиального размышления я пришел с «фабрикой» для обработки повторного использования NSDateFormatters на основе требуемого формата и локали.Я запрашиваю форматер даты некоторого формата и локали, и мой класс передает мне уже загруженный форматер.Хорошая настройка производительности, вы должны попробовать.

PS: Может быть, кто-то хотел бы проверить это, поэтому я обнародовал это: https://github.com/DougFischer/DFDateFormatterFactory/blob/master/README.md

...