为什么分配或初始化NSDateFormatter被认为是"昂贵的"?

Dra*_*aco 45 nsdateformatter ios

当人们说这很贵时,人们的意思是什么?我为中间存储创建了许多瞬态对象的实例(NSString和NSDate是典型的).我怎么知道我的程序使用NSDateFormatter是否过度了?

到目前为止,我倾向于创建相当于单身的东西,但我的偏好是将其封装到与之关联的其他一些对象中,以便我可以使用自引用.

没有运行性能测试,我正在寻找一个更好的"经验法则"理解为什么我应该或不应该这样做.

Ell*_*eal 39

当这样的事情被称为昂贵时,并不一定意味着你永远不应该这样做,它只是意味着避免在你需要尽快摆脱方法的情况下这样做.例如,当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;
}
Run Code Online (Sandbox Code Playgroud)

这段代码的滚动性能非常糟糕.帧速率下降到大约15 FPS,因为我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;
}
Run Code Online (Sandbox Code Playgroud)

这里的不同之处在于我懒洋洋地将其加载NSNumberFormatter到ivar中,因此每次运行tableView:cellForRowAtIndexPath:都不再分配新实例.这个简单的改变将滚动性能提升到大约60 FPS.

这个具体的例子不再那么相关,因为较新的芯片能够在不影响滚动性能的情况下处理分配,但最好尽可能提高效率.

  • 只是一个更新,在iOS7 + NSNumberFormatter是线程安全的. (9认同)

Dou*_*her 7

我前一段时间也有同样的问题.我在一些我工作的应用程序上运行了Instruments,并且我发现以前的开发人员正在为他们所做的每个自定义日志创建一个新的NSDateFormatter.因为对于每个屏幕,他们用来记录大约3行.该应用程序过去只花了大约一秒钟创建NSDateFormatters.

简单的解决方案是将日期格式化程序实例保留在类中作为属性或其他内容,并将其重用于每个日志行.

经过一些微不足道的思考,我带来了一个"工厂"来处理基于格式和想要的语言环境的NSDateFormatters的重用.我请求一些格式和语言环境的日期格式化程序,我的类给我已经加载的格式化程序.良好的性能调优,你应该试试.

PS:也许有人想测试它,所以我把它公之于众:https://github.com/DougFischer/DFDateFormatterFactory/blob/master/README.md