更改 NSMutableDictionary 的值时崩溃

Posted

技术标签:

【中文标题】更改 NSMutableDictionary 的值时崩溃【英文标题】:Crash while changing value of a NSMutableDictioanary 【发布时间】:2017-05-17 10:28:35 【问题描述】:

我需要一些关于 Swift 3.0 中 NSArray 中的 NSMutableDictionary 的帮助。 该结构是一个字典数组

这是我的代码

class abc
    var myTempArr : NSArray! 
 

  // I need objC variables as I need to pass them as reference

 someMethod()
    myTempArr = [["title":"abc","id":"1"]] // creating a dictionary inside the array
   // I have changed the value like this also, but the crash remains
   // [["title":"abc","id":"1"] as! NSMutableDictionary]


 


// This method is called in every key stroke in keyboard. Lets say we replace the "title", with the letter in the keyboard it is tapped

 func someotherMethod()
      let firstDictionary = myTempArr[0] as! NSMutableDictionary
      // Its crashing here!!!!
      // Again i need nsmutabledictionary as i need to change the value
      // inside the dictionary so that the value inside the main array
      // that is myTempArr also changes. I need a pass by reference
      // method, hence i choosed NSMutableDictionary instead of swift dictionary

      firstDictionary["title"] = "New Title"
      // After this line, the original dictionary inside myTempArr
      // should change as well. But its crashing in the mentioned line

 

我不想使用类实例,因为我知道它们也是通过引用传递的,但我需要应用 Predicate 来在数组中查找正确的字典,而不是按索引搜索。这也是我无法理解的概念。请帮我解决这个问题。

崩溃说:

无法转换“Swift._SwiftDeferredNSDictionary”类型的值 (0x7facdb71e6c0) 到 'NSMutableDictionary' (0x102bfa350)。

[编辑]

许多人建议选择将字典放入变量中,更改变量然后替换数组中的字典。好吧,我想避免这种方法,因为这与使用基于值的解决方案(Swift Dictionary,其按值传递)相同。我想避免这种情况的原因是,我使用的原始 DS 有大量的字典,并且字典的值经常变化。因此我不认为使用替换字典的方法是正确的。

我也知道 swift 这不好,因为 swift 不是为此而设计的。这种方法在 Objective C 中工作得非常好,因为我们改变变量(提示:变量指针),改变它最初来自的变量。 如果有人可以在 Swift 中提出替代或好的方法,那么请它会很棒。

另外,为了简单起见,我使用了 0 的索引。因为只有 1 个字典。但是在原始 DS 中,我提到了很多字典,因此我使用谓词。这也是我没有使用类的实例(也在 swift 中通过引用传递)的原因,因为当我们通过谓词搜索类的实例时,我不知道它们的行为是否像字典一样。

非常欢迎任何解决方案或替代方案。一如既往地感谢你们为此付出时间,因为我正在努力思考如何采用新方法

【问题讨论】:

如果你想要一个NSMutableDictionary,那么你需要明确地创建一个,但是如果你有一个依赖副作用的函数,那么你可能应该重新考虑你的设计。使用不变性可以提供更健壮的代码。 是的,我同意,不变性是要走的路,但我需要处理一个由带有字典数组的数据结构提供支持的表单。现在,每次我通过该表单编辑字典中的任何内容时,我都需要更改字典的确切值。现在这种设计方法不适用于 Swift。但是,如果您能建议任何其他设计或模型,那就太好了。但直到现在我需要解决这个问题 使用自定义类而不是字典和 Swift Array。这也为您提供了参考语义。只要你可以在 Swift 中避免NSMutableArray / -Dictionary,就去做吧! 会在自定义类工作上做谓词,因为他们在 swift 中工作字典?如您所知,我是 swift 新手,所以请原谅提出这样的问题 当然可以,但建议也使用像filter这样的原生函数。 【参考方案1】:

我建议字典可能是存储在数组中的错误数据结构。您已经指出字典代表某种形式的表单域。您可以创建一个对象来对这些字段进行建模,然后在仍然使用不可变数组的同时利用对象的可变性。

类似:

class Field 

    let id: Int
    let name: String
    var value: String

    init(id: Int, name: String, value: String = "") 
        self.id = id
        self.name = name
        self.value = value
    



let firstNameField = Field(id:1, name:"FirstName")
let surnameField = Field(id:2, name:"Surname")

firstNameField.value = "Paul"

var fieldsArray = [firstNameField,surnameField]

firstNameField.value = "Peter"

print(fieldsArray[0].value)  // Prints Peter

if let field1 = fieldsArray.first(where: $0.id == 1 )     
    print(field1.value)  // Prints Peter
    field1.value = "John"


print(fieldsArray[0].value)  // Prints John

请注意,由于Field 是一个类,我们能够使用引用语义,并且不必改变数组,因此对数组的修改操作没有副本。

【讨论】:

正如我在问题中提到的,我需要谓词搜索所有实例以查找 var id 中的某个键。这可能吗?或者更确切地说,如果更改经常发生,我会更有效率。这类问题还有其他方法吗? 这就是我在where 声明中展示的内容。但是,如果您知道要搜索哪个属性,那么创建由搜索属性键入的字段的字典可能更有效,因为搜索字典是 O(logn),而搜索数组是 O(n)。也可能有其他优化。当它成为第一响应者时,您可以识别该字段,因此无需不断搜索数组;您可以保持对当前字段的引用,直到选择另一个字段。 感谢您的提示。如果可能的话,我想和你讨论更多关于 swift 3 的设计模式,再次感谢。【参考方案2】:

试试这个

let firstDictionary = NSMutableDictionary(dictionary: myTempArr[0])

【讨论】:

当我在此过程中更改firstDictionary 中的任何内容时,这不会更改主数组myTempArr 那么你需要用firstDictionary里面的myTempArr替换旧字典。 不能这样做,因为我正在使用的数组很大,并且任何事件更改都可能发生在数据结构上的几乎所有事件中,即在每个键盘按钮点击中。因此不能通过替换逻辑。请给我一些建议,感谢你们给我的时间:) 您的主数组myTempArr 是不可变的NSArray。即使您从该数组中获取字典的实例,它也是不可变的。正如 Paulw11 所说,您需要重新考虑您的逻辑。【参考方案3】:

您可以这样定义 myTempArr:

func someMethod()
    let nsmutabledict = NSMutableDictionary(dictionary: ["title":"abc","id":"1"])
    myTempArr = [nsmutabledict]


【讨论】:

【参考方案4】:

导致代码崩溃的原因是NSArray,需要更改为NSMutableArray,因为下标不支持NSArray 的可变行为。


检查下面的代码并在您的代码运行后进行更改:-

var myTempArr: NSMutableArray = [["title":"abc","id":"1"]] //Should be mutable for updating information
let dictionary = myTempArr[0] as? NSMutableDictionary ?? [:] //Getting here dictionay(Key value here)
dictionary["title"] = "New Title"  //Changing here value
myTempArr[0] = dictionary  //Finally updating on main array details

否则,可以试试下面的代码:-

var array = [["title":"abc","id":"1"]] //Mutable Array
var dictionary = myTempArr[0] as? [String: String] ?? [:] //Getting here values
dictionary["title"] = "New Title" //Changing value
myTempArr[0] = dictionary // Updating Main array value

代码输出:-

【讨论】:

这行不通。您不能从文字创建 NSMutableArray 只是注释类型。而且你不能在 Swift 中向NSMutableDictionary 投射任何东西。 我刚刚转换了一种数据来解释。 @vadian NSMutable... 集合类型在 Swift 中是没有希望的,因为它们不相关并且不能转换为原生 Swift 对应对象。 我知道所有与swift相关的事情,但是一旦我在那里添加了新东西,请检查我的答案。 @vadian 这可行,但正如我所说,我不能继续替换主数组中正在更改的字典。我想要一个通过引用传递的解决方案,其中字典变量的更改将推动数组本身的原始更改。【参考方案5】:

因为字典是不可变的。你不能这样投射它。 你可能想做这样的事情:

编辑:好的,这应该对你有用:

var tempArray: Array<Dictionary<String,String>>!

初始化...

tempArray = [["title":"abc","id":"1"]] 

然后像这样编辑字典:

func someotherMethod() 
     tempArray[0]["title"] = "New Title" 

编辑: 我不知道 - 听听你的 cmets,也许这样的东西对你有用?

关于获取正确字典的问题:

双重编辑:

if let dictionaryIndex = tempArray.index(where: $0["title"] == "abc") 
        tempArray[dictionaryIndex]["title"] = "NOT ABC"

新兴城市。您可以通过 == 检查获得所需的准确字典,然后更改准确的可变 tempArray 值。

【讨论】:

为什么要投反对票?我同意向下转换 + 在 swift 中使用 NS 类不是最好的选择,但这就是问题所在。 我已经将它转换为 NSMutableDictionary 并且它只在该行崩溃。此外,采用这种方法,主数组不会改变。总是替换字典不是一种选择,因为这是一个演示数组,它可能包含数千个字典,并且可能会改变说:每个按键。 请阅读我的评论,因为我写了这种方法有什么问题 不能这样做,因为我需要使用另一个变量来捕获 EXACT 字典,因为我使用谓词来过滤 THAT Exact 字典而不是 INDEX。因此将您的代码应用于该逻辑,问题仍然存在 在您的问题中,您使用的索引为 0,所以我在我的问题中使用了索引。您想在索引 0 处更改字典的标题,而我的代码就是这样做的。如果这不能解决您的问题,也许您应该添加到您的问题中,即您实际需要帮助的内容。通过 Playground 运行我的代码完全符合您在问题中提出的要求。

以上是关于更改 NSMutableDictionary 的值时崩溃的主要内容,如果未能解决你的问题,请参考以下文章

NSMutableDictionary 中的更改未反映在父 NSDictionary 中

在从 NSMutableDictionary 加载的 textview 中保存更改的文本

“NSMutableDictionary”类型的值在 swift 中没有成员“字符串”

按字典键的值对包含 NSMutableDictionary 的 NSMutableArray 进行排序

如何更改 NSMutableDictionary int 值

如何从 nsmutabledictionary 中删除键当该键的值在 ios 中为空或 null 时?