Search code examples
iosswift3nsarraynsdictionary

Crash while changing value of a NSMutableDictioanary


I need some help with NSMutableDictionary inside NSArray in Swift 3.0. The structure is an Array of Dictionaries

This is my code

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

 }

I dont want to use class instances as I know they are also pass by reference but I need to apply Predicate to finding the correct dictionary inside the array, instead of searching by index. This is also a concept I cannot understand. Please help me figure this out.

The crash says :

Could not cast value of type 'Swift._SwiftDeferredNSDictionary' (0x7facdb71e6c0) to 'NSMutableDictionary' (0x102bfa350).

[EDIT]

As many people are suggesting the option of getting the Dictionary in a variable, changing the variable and then replacing the dictionary in the array. Well this approach I want to avoid, as this would be the same as using value based solution (Swift Dictionary where its passed by value). The reason I want to avoid this is because, the original DS I am using has a huge number of dictionaries and values of dictionary are changing very often. Hence I dont think using the replace Dictionary approach would be sound.

Also I know in swift this is not good, as swift was NOT designed for this. This approach works perfectly fine in Objective C, as we changing variables (cue : Pointers of variables), changes the variable it was originally from. If anyone can suggest an alternate or good approach in Swift, then please It would be awesome.

Also for the sake of simplicity I have used an index of 0. as there is only 1 dictionary. But in the original DS, there are a lot of dictionaries as I mentioned, hence I am using predicate. This is also a reason why I didnt use instance of a class (also pass by reference in swift), as I dont know if instances of class behave like dictionaries when we search them by Predicate.

Any solution or alternative is highly welcome. As always thank you guys for giving time to this, as I am trying to wrap my head around how to go for a new approach


Solution

  • I would suggest that a dictionary is probably the wrong data structure to store in your array. You have indicated that the dictionaries represent some sort of form fields. You can create an object to model these fields and then take advantage of the mutability of objects while still using immutable arrays.

    Something like:

    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
    

    Note that since Field is a class we were able to use reference semantics and never had to mutate the array, so there were no copy on modify operations on the array.