【问题标题】:Is it possible to have a dictionary with a mutable array as the value in Swift是否有可能有一个带有可变数组的字典作为 Swift 中的值
【发布时间】:2014-07-20 21:48:00
【问题描述】:

我正在尝试这样做:

var dictArray = [String:[String]]()
dictArray["test"] = [String]()
dictArray["test"]! += "hello"

但我收到了奇怪的错误NSString is not a subtype of 'DictionaryIndex<String, [(String)]>'

我只是希望能够将对象添加到字典内的数组中。

更新:看起来 Apple 认为这是 Swift 中的“已知问题”,这意味着它将按预期工作最终。来自 Xcode 6 Beta 4 发行说明:

...同样,您不能修改可变的基础值 可选值,有条件地或在强制展开中:

tableView.sortDescriptors! += NSSortDescriptor(key: "creditName", ascending: true)

解决方法:显式测试可选值,然后分配 结果返回:

if let window = NSApplication.sharedApplication.mainWindow {
    window.title = "Currently experiencing problems"
}
tableView.sortDescriptors = tableView.sortDescriptors!

【问题讨论】:

  • 从 Xcode 7.2 开始仍然无法正常工作?
  • SE-171 解决了reduce 的类似问题。也许我们将来会看到 forEachmap 带有带有 inout 参数的函数参数!

标签: dictionary swift


【解决方案1】:

您可以使用 NSMutableArray 而不是 [String] 作为字典的值类型:

var dictArray: [String: NSMutableArray] = [:]
dictArray["test"] = NSMutableArray()
dictArray["test"]!.addObject("hello")

【讨论】:

    【解决方案2】:

    你只能这样做

    var dictArray = [String:[String]]()
    dictArray["test"] = [String]()
    var arr = dictArray["test"]!;
    arr += "hello"
    dictArray["test"] = arr
    

    因为dictArray["test"] 给你Optional<[String]> 这是不可变的

      6> var test : [String]? = [String]()
    test: [String]? = 0 values
      7> test += "hello"
    <REPL>:7:1: error: '[String]?' is not identical to 'UInt8'
    

    append 也因为同样的原因不能工作,Optional 是不可变的

      3> dictArray["test"]!.append("hello")
    <REPL>:3:18: error: '(String, [(String)])' does not have a member named 'append'
    dictArray["test"]!.append("hello")
                     ^ ~~~~~~
    

    顺便说一句,错误信息太可怕了……

    【讨论】:

    • 这正在慢慢杀死我
    • 要明确:这不会更新存储的值,而是使用更新的副本更新它。
    【解决方案3】:

    这在 Swift 3 中仍然是一个问题。至少我能够创建可以为您处理它的方法。

    func appendOrCreate(newValue: Any, toArrayAt key: String, in existingDictionary: inout [AnyHashable:Any]) {
    
        var mutableArray = [Any]()
    
        if let array = existingDictionary[key] as? [Any]{
            //include existing values in mutableArray before adding new value
            for existingValue in array {
                mutableArray.append(existingValue)
            }
        }
    
        //append new value
        mutableArray.append(newValue)
    
        //save updated array in original dictionary
        existingDictionary[key] = mutableArray
    }
    

    【讨论】:

      【解决方案4】:

      问题是我们在这里需要类语义,但必须使用结构。如果你把类对象放入字典,你就会得到你想要的!

      因此,如果您拥有¹ 具有可变值,则可以将它们包装在一个类中并使用闭包执行更新:

      class MutableWrapper<T> {
          var rawValue: T
      
          init(_ val: T) {
              self.rawValue = val
          }
      
          func update(_ with: (inout T) -> Void) {
              with(&self.rawValue)
          }
      }
      

      例子:

      func foo() {
          var dict = [String: MutableWrapper<[String]>]()
      
          dict["bar"] = MutableWrapper(["rum"])
          dict["bar"]?.update({$0.append("gin")})
      
          print(dict["bar"]!.rawValue)
          // > ["rum", "gin"]
      }
      

      对于它的价值,我看不到保持调用者和包装器同步的方法。即使我们声明init(_ val: inout T),我们最终也会在rawValue 中得到一个副本。


      1. 性能不一定是问题,因为编译器会大量优化结构。我会将任何可变解决方案与代码中的大量复制更新进行基准测试。

      【讨论】:

        【解决方案5】:

        从 Swift 4.1 开始,你可以provide a default value to the subscript 让你现在很自然地解决这个问题:

        dictArray["test", default: []].append("hello")
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-09-08
          • 2012-03-01
          • 1970-01-01
          • 2020-10-15
          • 2018-12-20
          • 1970-01-01
          相关资源
          最近更新 更多