【问题标题】:How does one create a mutable copy of an immutable array in swift?如何快速创建不可变数组的可变副本?
【发布时间】:2014-07-13 10:09:02
【问题描述】:

现在 Swift 的数组是真正不可变的,这要归功于全值语义,我如何创建不可变数组的可变副本?类似于 Obj-C mutableCopy()。我当然可以将数组向下转换为 NSArray 并使用 mutableCopy() 但不想使用 NSArray 因为它没有严格键入。

我有一个toolbar,其中有来自情节提要的items。我想从工具栏中删除一个项目并使用toolbar.setItems。我想在不强制转换为 NSArray 的情况下执行此操作,因为这些函数都没有采用 NSArrays,它们采用 [AnyObject]

显然现在当我打电话给removeAtIndex() 时它不起作用,这是正确的。我只需要一个 mutableCopy

简单地分配给 var 对我不起作用并给出 'Immutable value of type [AnyObject]'

var toolbarItems = self.toolbar.items
toolbarItems.removeAtIndex(2) //Immutable value of type [AnyObject]

我正在使用 Beta 3

【问题讨论】:

    标签: ios arrays swift


    【解决方案1】:

    问题在于self.toolbar.items 是一个隐式展开的可选项(类型为 [AnyObject]!)并且它们始终是不可变的。当您分配给变量toolbarItems 而不明确说明其类型时,它也将成为隐式展开的可选项,因此也是不可变的。

    要解决此问题,请执行以下任一操作:

    var toolbarItems:[AnyObject] = self.toolbar.items
    toolbarItems.removeAtIndex(2)
    

    或者:

    var toolbarItems = self.toolbar.items as [AnyObject]
    toolbarItems.removeAtIndex(2)
    

    更新

    从 Xcode 6 Beta 5 开始,您可以更新存储在可选变量中的集合,因此原始代码现在可以正常工作:

    var toolbarItems = self.toolbar.items
    toolbarItems.removeAtIndex(2)
    

    【讨论】:

    • 这几乎是我在回答中所说的,但简要解释了引擎盖下的内容 - 因此你应该得到我的支持
    【解决方案2】:

    数组是值类型(结构),因此它们是按值而不是按引用传递的。

    也就是说,如果您创建一个数组类型的变量并将其分配给不可变数组,则实际上会创建一个不可变数组的副本并将其分配给它 - 当然,该副本与原始不可变数组无关(除了在创建时具有相同的值)。

    let immutable = [1, 2, 3]
    
    //immutable[0] = 1 // Fails, ok
    
    var mutable = immutable
    
    mutable[0] = 5
    

    在您的情况下,您正在访问一个不可变数组,它是AnyObjects 的NSArray(请参阅documentation)。你可以在swift中将它作为一个数组使用,复制它并修改如下:

    let immutable : NSArray = [ 1, 2, 3 ]
    
    //immutable[0] = 1 // Fails, ok
    
    var mutable : [AnyObject] = immutable
    
    mutable.removeAtIndex(1) // mutable now is [1, 3]
    
    mutable[0] = 7 // mutable now is [7, 3]
    

    完成更改后,您可以分配给items 属性

    【讨论】:

    • 我认为问题在于self.toolbar.itemsNSArray。调查一下
    • 也许使用 NSArray,你需要更老派一点?试试var mutable = immutable.mutableCopy() as NSMutableArray
    • 阅读上面我的答案的补充
    • 啊哈。所以输入[AnyObject]就可以了。
    【解决方案3】:

    就像用你的数组声明一个var 一样简单。

    var items = toolbar.items
    

    现在您可以更改项目,然后重新分配给工具栏。

    toolbar.items = items
    

    请注意,您可以(从 Beta 3 开始)也不能更改用 let 声明的“不可变”数组的元素。只是数组 is 的长度是固定的,这就是为什么你不能删除项目。

    但是,根据 Apple 的 UIToolbar 文档,items 数组已经是可变的。

    SWIFT
    var items: [AnyObject]!

    【讨论】:

    • 查看我的编辑。我不确定这是否是因为 Beta 3?
    • 您的最新编辑(使用var b = a)在 Xcode build 6A254o 中运行良好。如果您尝试a[1] = 5,您将看到b 已按预期更改。
    • 是的,我是笨蛋,我不是故意的。我删除了它。这确实有效,但由于某种原因,self.toolbar.items 仍然是不可变的。而且我认为如果你分配它们,数组现在是完全不可变的。来自苹果的发布说明:“Swift 中的数组已被完全重新设计,以具有像 Swift 中的 Dictionary 和 String 一样的全值语义。这解决了各种可变性问题——现在 'let' 数组是完全不可变的,而 'var'数组是完全可变的”
    • @Mundi,我认为这在 beta 3 中不再有效,他们修复了它。您不能更改不可变数组中元素的值
    • 查看我的附加答案 - 我测试了它并且它有效。
    【解决方案4】:

    测试+作品:

        var mutable : [UIBarButtonItem] = []
        for button in toolbar.items {
            mutable += button as UIBarButtonItem
        }
        mutable.removeAtIndex(2)
        toolbar.setItems(mutable, animated: true)
    

    【讨论】:

      【解决方案5】:

      从数组的特定索引中删除对象。

      let fullArray : NSArray = Userdefaults().value(forKey: "YOUR_ARRAY_STRING") as! NSArray
      var mutableArray : [AnyObject] = fullArray as [AnyObject]
      mutableArray.remove(at: INDEX_TO_REMOVE) //Eg: mutableArray.remove(at: 0)
      mutableArray.append(ARRAY_TO_APPEND)
      

      【讨论】:

        【解决方案6】:

        在 Beta3 中,常量数组是完全不可变的,而变量数组是完全可变的。所以只需将 let array: 更改为 var array: ,然后验证您的代码

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-28
          相关资源
          最近更新 更多