【问题标题】:Differences between [NSArray arrayWithArray:] and [NSArray copy][NSArray arrayWithArray:] 和 [NSArray copy] 的区别
【发布时间】:2013-02-13 08:46:59
【问题描述】:

最近我经常使用数组,我想知道..这两行之间有什么区别。

NSArray *array = [NSArray arrayWithArray:someArray];

和

NSArray *array = [someArray copy];

哪个更快?如果我们有NSMutableArray 和mutableCopy 怎么办?

【问题讨论】:

    标签: objective-c cocoa-touch cocoa nsmutablearray nsarray


    【解决方案1】:

    哪个更快?

    别担心。过早的优化。

    主要区别:第一种方法会产生一个自动释放的“副本”,您不拥有也不必释放,而您确实拥有在第二行创建的对象。 顺便说一下,这两个数组都是不可变的。

    【讨论】:

    • ARC 怎么样?
    • 我会说 ARC 使用第二个,所以它不会自动释放,因此在刷新自动释放池之前不会保留。但同样,除非您在同一个运行循环(或在 @autoreleasepool 内)创建大量数组,否则这是过早的优化 :)
    • 我们应该使用哪一个?
    【解决方案2】:

    除了其他答案,还要注意,当someArray 为 nil 时, 第一行将使array 指向一个空数组,第二行将使 它指向零。这可能是一个重要的区别,尤其是在可变数组中。

    【讨论】:

    • 我们应该使用哪一个?
    【解决方案3】:

    两者的区别在于后者会被保留。前者将被自动释放。

    两个版本都制作了数组的浅拷贝。

    NSMutableArray *notMutableReally = [NSArray arrayWithArray:aMutableArray];
    

    应该给您一个编译器警告,因为您将尝试将 NSArray 分配给 NSMutableArray。

    使用。

    NSMutableArray *mutableArrayCopy = [NSMutableArray arrayWithArray:aMutableArray];
    

    哪个更快?别担心,它们都比您将要做的其他事情快得多。如果您真的在乎,请与 Instruments 联系。

    【讨论】:

      【解决方案4】:

      主要区别在于-copy 更了解如何复制自身(可以更有效地进行复制,并且可能使用更适合的 NSArray 子类),而+arrayWithArray: 将创建 NSArray 的新实例(嗯,在事实上 Foundation 用于数组的具体类)并使用与初始对象相同的对象列表提供给它。它还会添加一个额外的自动释放。

      所以-copy(非常非常)可能更有效。

      事实上对于不可变的NSArrays,-copy 只是在做-retain,所以它甚至不需要创建一个新实例。

      【讨论】:

      • 这不准确。复制时正在创建一个新数组。
      • 你可以用一个简单的测试工具试一试(更不用说我还有其他非常好的理由相信我在这里是正确的?)
      • @Julien 因为您似乎非常精通 Foundation 类,所以检查 NSArray、NSDictionary 等是否可变的正确方法是什么?已经在其他地方进行了讨论,但没有找到好的答案? (-isKindOfClass: 据说不可靠,不确定 -respondsToSelector:@selector(addObject:) 的东西?)正在寻找正确的方法......谢谢!
      • 没有坏的黑客是不可能的(并且对于未来或过去版本的 Foundation 可能不可靠。事实上,你不应该这样做(或者很可能是什么错误你正在尝试做)。
      【解决方案5】:
      NSMutableArray *arr = [NSMutableArray array];
      for ( int i = 0; i < 10000; i ++)
      {
          [arr addObject:@(i*1000000ULL)];
      }
      // MARK
      // arr = (id)[NSArray arrayWithArray:arr];
      
      NSTimeInterval t = [NSDate timeIntervalSinceReferenceDate];
      NSArray *res = nil;
      for ( int i = 0; i < 10000; i ++)
      {
          res = [arr copy];
      }
      NSLog(@"time A: %f", [NSDate timeIntervalSinceReferenceDate] - t);
      t = [NSDate timeIntervalSinceReferenceDate];
      for ( int i = 0; i < 10000; i ++)
      {
          res = [NSArray arrayWithArray:arr];
      }
      NSLog(@"time B: %f", [NSDate timeIntervalSinceReferenceDate] - t);
      

      时间 A:1.572795,时间 B:1.539150,B [NSArray arrayWithArray:] 总是更快,但时间差非常小。 但是如果我们取消注释 "MARK" 并从 NSArray 获取副本而不是 NSMutableArray 我们将有其他运行时 A: 0.000473 时间 B: 1.548400 结果: ~3200 倍快

      【讨论】:

        【解决方案6】:

        其中一个可能更快。运行它们一百万次,看看是否有人获胜。

        在NSArray 与NSMutableArray 的情况下,被复制的不可变数组不必实际返回副本,因为它无法更改。但是,如果您有一个可变数组,则需要复制它,因为您可以更改原始数组。当然,做一个可变副本总是需要返回一个新对象。

        在您的整个应用程序中,速度和内存差异可能与正在发生的其他事情相比并不重要。

        【讨论】:

          【解决方案7】:

          在 Swift 中,情况非常不同。感谢新的 Swift 开源基金会,我们知道 init(array:) 使用给定的项目(如果有)创建一个新数组,copy() 只返回 self。

              public override func copy() -> AnyObject {
                  return copyWithZone(nil)
              }
          
              public func copyWithZone(zone: NSZone) -> AnyObject {
                  return self
              }
          

          https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L82

              public convenience init(array: [AnyObject]) {
                  self.init(array: array, copyItems: false)
              }
          
              public convenience init(array: [AnyObject], copyItems: Bool) {
                  let optionalArray : [AnyObject?] =
                      copyItems ?
                          array.map { return Optional<AnyObject>(($0 as! NSObject).copy()) } :
                          array.map { return Optional<AnyObject>($0) }
          
                  // This would have been nice, but "initializer delegation cannot be nested in another expression"
          //        optionalArray.withUnsafeBufferPointer { ptr in
          //            self.init(objects: ptr.baseAddress, count: array.count)
          //        }
                  let cnt = array.count
                  let buffer = UnsafeMutablePointer<AnyObject?>.alloc(cnt)
                  buffer.initializeFrom(optionalArray)
                  self.init(objects: buffer, count: cnt)
                  buffer.destroy(cnt)
                  buffer.dealloc(cnt)
              }
          

          https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/NSArray.swift#L116

          所以,很明显,copy() 更快,现在您知道它们是如何工作的了! (仅在 Swift 中)

          【讨论】:

            猜你喜欢
            • 2010-11-23
            • 1970-01-01
            • 1970-01-01
            • 2016-02-18
            • 2014-11-09
            • 2012-10-01
            • 2010-12-08
            • 2011-01-01
            相关资源
            最近更新 更多