【问题标题】:Modifying an array of dictionaries in Swift在 Swift 中修改字典数组
【发布时间】:2014-09-22 16:40:58
【问题描述】:

我是 Swift 新手,在搞清楚数组和字典的某些方面时遇到了一些麻烦。

我有一个字典数组,为此我使用了类型别名 - 例如

typealias myDicts = Dictionary<String, Double>

var myArray : [myDicts] = [
["id":0,
    "lat”:55.555555,
    "lng”:-55.555555,
    "distance":0],
["id":1,
    "lat": 44.444444,
    "lng”:-44.444444,
    "distance":0]
]

然后我想遍历数组中的字典并更改“距离”键值。我是这样做的:

for dict:myDicts in myArray {

dict["distance"] = 5

}

或者甚至明确地确保 5 是一个双精度数,包括许多不同的方法,例如

for dict:myDicts in myArray {

let numberFive : Double = 5

dict["distance"] = numberFive

}

我所有的尝试都会导致错误:

 @lvalue $T5' is not identical to '(String, Double)

看起来好像里面的字典是不可变的“let”而不是“var”。所以我随机尝试了这个:

for (var dict:myDicts) in myArray {

dict["distance"] = 5

}

这消除了错误,并且在 for 循环中确实为键分配了 5,但从长远来看,这似乎并没有真正修改数组本身。我做错了什么?

【问题讨论】:

    标签: arrays dictionary swift


    【解决方案1】:

    在 Swift 的 for-in 循环中隐式声明的变量默认是常量(let),这就是为什么你不能直接在循环中修改它的原因。

    for-in documentation 有这个:

    for index in 1...5 {
        println("\(index) times 5 is \(index * 5)")
    }
    

    在上面的例子中,index 是一个常量,它的值是自动 在循环的每次迭代开始时设置。因此,它不 必须在使用前声明。它是隐式声明的 只需将其包含在循环声明中,无需 一个 let 声明关键字。

    正如您所发现的,您可以通过使用var 显式声明它来使其成为变量。但是,在这种情况下,您正在尝试修改作为结构的字典,因此是 value type 并且它在分配时被复制。当您执行dict["distance"] = 5 时,您实际上是在修改字典的副本,而不是存储在数组中的原始字典。

    你仍然可以修改数组中的字典,你只需要直接通过索引循环数组来完成:

    for index in 0..<myArray.count {
        myArray[index]["distance"] = 5
    }
    

    这样,您肯定会修改原始字典而不是它的副本。

    话虽如此,@matt 建议使用自定义类通常是最好的选择。

    【讨论】:

      【解决方案2】:

      你没有做错任何事。这就是斯威夫特的工作方式。你有两个选择:

      • 使用 NSMutableDictionary 而不是 Swift 字典。

      • 使用自定义类而不是字典。在某种程度上,这是一个更好的解决方案,因为在所有字典都具有相同结构的情况下,您应该一直这样做。

      我所说的“自定义类”只是一个“值类”,是一组属性。这在 Objective-C 中是一种痛苦,但在 Swift 中它是微不足道的,所以我现在经常这样做。问题是您可以将自定义类的类定义粘贴到任何地方;它不需要自己的文件,当然在 Swift 中你没有接口/实现 foo 来处理,更不用说内存管理和其他东西了。所以这只是几行代码,您可以直接使用已有的代码。

      这是我自己的代码中的一个示例:

      class Model {
          var task : NSURLSessionTask!
          var im : UIImage!
          var text : String!
          var picurl : String!
      }
      

      然后我们有一个模型数组,然后我们就走了。

      所以,在你的例子中:

      class MyDict : NSObject {
          var id = 0.0
          var lat = 0.0
          var lng = 0.0
          var distance = 0.0
      }
      
      var myArray = [MyDict]()
      
      let d1 = MyDict()
      d1.id = 0
      d1.lat = 55.55
      d1.lng = -55.55
      d1.distance = 0
      let d2 = MyDict()
      d2.id = 0
      d2.lat = 44.44
      d2.lng = -44.44
      d2.distance = 0
      myArray = [d1,d2]
      
      // now we come to the actual heart of the matter
      
      for d in myArray {
          d.distance = 5
      }
      println(myArray[0].distance) // it worked
      println(myArray[1].distance) // it worked
      

      【讨论】:

      • 谢谢 - 使用自定义类似乎是个好主意。但是我在我的项目中实现它时遇到了一些麻烦......你能给我一个例子,说明它如何与我的问题中的例子一起工作吗?
      • 当然可以,但这非常简单明了;我不应该为你写代码。
      • 抱歉,我只是需要进一步说明。这并不是说我需要专门为我的代码提供一个示例,而是在一个完整的上下文中看到整个操作确实对那些不熟悉这方面的人很有帮助。我现在明白了!
      • 请注意,可以在这里编写一个更优雅的值类。我只是向您展示最小的可能课程!例如,如果类有一个不错的初始化程序,这会好很多。 :)
      【解决方案3】:

      是的,在循环中检索到的字典是不可变的,因此您无法更改。 恐怕您的最后一次尝试只是创建了它的可变副本。

      一种可能的解决方法是使用NSMutableDictionary

      typealias myDicts = NSMutableDictionary
      

      【讨论】:

        【解决方案4】:

        有一个 Swift 字典或数组的类包装器。

        class MyDictionary: NSObject {
        var data : Dictionary<String,Any>!
        init(_ data: Dictionary<String,Any>) {
            self.data = data
        }}
        
        MyDictionary.data
        

        【讨论】:

          猜你喜欢
          • 2014-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-10
          相关资源
          最近更新 更多