【问题标题】:What is the best way to initialize NSMutableString object?初始化 NSMutableString 对象的最佳方法是什么?
【发布时间】:2012-01-28 01:10:21
【问题描述】:

如果我回答以下问题。初始化 NSMutableString 类的最佳方法是什么? (所有实例都会在意想不到的时候返回......所以我假设初始化如下:)

  1. 如果我提前知道工作量。 (预期)

    NSMutableString *str1 = [NSMutableString stringWithString:@""];
    NSMutableString *str2 = [NSMutableString stringWithCapacity:0];
    NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
    NSMutableString *str4 = [NSMutableString string];
    
    for(int i = 0; i< 1000; i++)
    {
        //The following tasks.(Adding to the string to continue working.)
        [/*str1~str4*/ appendFormat:@"%d", i];
    }
    
  2. 如果我事先不知道工作量。 (意外)

    NSMutableString *str1 = [NSMutableString stringWithString:@""];
    NSMutableString *str2 = [NSMutableString stringWithCapacity:0];
    NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
    NSMutableString *str4 = [NSMutableString string];
    
    for(int i = 0; i< /*a large of size(unpredictable)*/ ; i++)
    {
        //The following tasks.(Adding to the string to continue working.)
        [/*str1~str4*/ appendFormat:@"%d", i];
    }
    

在执行这些任务时大体上一分为二,初始化的最佳方式是什么?

我有时在处理这些任务时也会感到困惑。

【问题讨论】:

    标签: iphone objective-c nsstring nsmutablestring


    【解决方案1】:

    如果您事先知道尺寸,请使用

     [NSMutableString stringWithCapacity: _Known_Size_];
    

    如果您事先不知道尺寸,请使用

     [NSMutableString stringWithCapacity: _small_number_];
    

    然后可变字符串将根据需要增长。

    【讨论】:

      【解决方案2】:

      分配和初始化一个对象总是更好,而不是使用类方法来创建它(将它放在最近的自动释放池中)。

      所以,

      NSMutableString* stringOne = [[NSMutableString alloc] initWithCapacity:capacity];
      

      而不是

      NSMutableString* stringTwo = [NSMutableString stringWithCapacity:capacity];
      

      请记住,您必须在完成后释放 stringOne,而不是 stringTwo,因为 stringWithCapacity: 类方法返回一个自动释放的对象。

      在此处阅读有关该主题的更多信息:http://www.mulle-kybernetik.com/artikel/Optimization/opti-5.html

      【讨论】:

      • 并不总是更好,不。在很多情况下,它带给你的只是更多的 LOC。
      • @Rickay,stringOne 比 stringTwo 更好吗?
      • 这不是“更好”,但在性能方面,自己手动分配和释放内存更有效。代码有点多,但如果要分配大量字符串会更好。
      【解决方案3】:

      没关系。

      如果到目前为止您已经优化了您的程序,这一决定将对它的整体性能产生可衡量的影响,请拍拍自己的后背,或者就像 BBT 的 Sheldon 所说的那样,“吃块巧克力!”

      PS:
      如果您预先知道大小或对它有一个非常好的估计,然后在stringWithCapacity: 或initWithCapacity: 中使用该大小,如果您不知道,那么甚至不要打扰 - 让框架决定,it's pretty damn clever !

      【讨论】:

      • +1。如果您觉得有必要检查它们,您可以检查它们的特定聪明才智(opensource.apple.com/source/CF/CF-635/CFString.c 中的__CFStrNewCapacity())。但这通常不是您应该尝试优化的地方。如果您要创建如此多的字符串,这很重要,那么通过重用字符串对象而不是优化它们的初始创建,您将获得更好的性能。
      【解决方案4】:

      案例 1

      在列出的选项中,我会使用:

      NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
      

      ...如果您知道目标大小,或者在顶部留出一点空间来估计它,并且能够快速确定确切的大小,或者最坏情况下的大小,这可以节省多次重新分配和复制操作。如果你不知道最坏情况下的大小,或者计算需要很长时间,那么你不妨使用[NSMutableString string] 或[NSMutableString new]。此外,*WithCapacity 是一个提示,框架可以随意忽略。

      当然,你的循环体和你保留的大小也意味着所有的值都是 [0…9] (具体来说,所有值都消耗一个字符),在这种情况下,你可能会做得更好使用带有更多参数的格式字符串。但是,i 对于大多数迭代而言显然大于 9,并且平均每个会消耗 3 个字符,因此对于您发布的确切代码,3000 将是更合适的保留容量。

      案例 2

      在列出的选项中,我会使用:

      NSMutableString *str4 = [NSMutableString string];
      

      如果您不需要将其添加到自动释放池中,那就更好了:[NSMutableString new] 或 [[NSMutableString alloc] init]。

      其他说明

      是的,将对象排除在自动释放池之外(例如,使用 alloc+init)可以显着提高性能并减少峰值内存使用量。有时,这超出了您的控制范围,并且在某些环境(例如 ARC)中,即使您使用自动释放的便利构造函数,也可能会发生这种情况 - 例如[NSMutableString string].

      更快的解决方案

      最后,如果您概述的这种情况确实是性能问题,最快的方法是在堆栈上创建一个 char 缓冲区,然后从将数字复制到 @ 的结果中创建一个 NSString 987654332@ 缓冲区。假设您的 ints 都是 0-9,这将非常快速和容易,然后只需从(终止的)cstring 创建一个 NSString。如果输入大小不同或非常大(导致字符串很长),您甚至可以这样做。

      【讨论】:

      • @autoreleasepool 块和在作用域结束时手动释放之间的内存使用差异应该不会那么大。因此,除非您在代码中全部发布(这确实可以更快地释放内存,但 IMO 更难看出您是否完全发布了它),我对大多数情况下的差异持怀疑态度。出于好奇,您对此有什么确切的数字吗?
      • @Chuck 然而,这并不是典型的现实世界执行——很少有开发人员定期明确地创建自动释放池(除了新线程/程序的条目)。因此对象的池和依赖项经常变大。还有许多因素会降低性能,不仅仅是分配计数。相信人们可以/应该忘记“系统有效地自动处理”会导致问题(续)
      • (cont) 与需要大量进程 CPU 时间的 objc 垃圾收集活动不同(来自 OS X 的真实示例)。是的,我已经广泛优化了许多可可程序。它的缺点是:显式控制和最小化对象的生命周期,在适当的地方使用不可变类型等可以使程序的执行速度提高几倍。 Rickay 的帖子中存在一个链接(您也对此发表了评论,所以...我会假设您看到了它)。
      • 我只是怀疑这在大多数情况下是否矫枉过正。 Rickay 帖子中的链接指出这是一种优化,并展示了如何做到这一点。它并没有说明这比明智地使用自动释放池更好的时间或程度。它还推荐allocWithZone: 和对象池的一些不太确定的实现。无论如何,如果您使用本地范围之外的引用构建了一个非常复杂的对象图,那么 真的 您使用哪种释放方法并不重要,因为无论如何这些对象都不会立即释放你释放它们。
      • @Chuck 看来您选择保持怀疑。并且您评论中的最后一点是错误的,因为在大多数情况下会创建大量瞬态对象,它们的销毁可以更快地发生,并且它们的内存可以更快地返回。因此,假设您构建了一些复杂的东西,例如窗口或复杂视图,是否存在临时的、自动释放的对象,这些对象不需要添加到自动释放池中,也不需要超出分配它们的范围?当然。
      【解决方案5】:

      这是最短的方法:

      NSMutableString *string = [@"" mutableCopy];
      

      【讨论】:

      • 这需要创建一个空的 NSString (@""),然后调用它的方法将其转换为可变的。效率不高。
      【解决方案6】:
      NSMutableString *str1 = [NSMutableString stringWithString:@""];
      

      糟糕,一个 NSString (@"") 被毫无意义地创建,然后复制到一个新的 NSMutable 字符串中

      NSMutableString *str2 = [NSMutableString stringWithCapacity:0];
      

      糟糕,容量为 0 的 NSMutableString 在第一次添加时需要膨胀。

      NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
      

      很好,如果 1000 有一定意义(即,它是您正在处理的内容的预期大小)。

      NSMutableString *str4 = [NSMutableString string];
      

      好,使用方便的方法,就像在做[NSMutableString alloc] init];

      【讨论】:

        【解决方案7】:

        在 Swift 5 中:

        var mutableString = NSMutableString("")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-09-17
          • 2015-07-16
          • 1970-01-01
          • 2012-02-08
          • 1970-01-01
          • 2019-07-24
          • 2017-11-01
          • 1970-01-01
          相关资源
          最近更新 更多