0
votes

What am I missing...?

elsewhere in my project there is code like this:

let allUsers = ["userName":["difficulty": 1, "highscore": 50],"userName2":["difficulty": 2, "highscore: 75]]          
defaults.setObject(allUsers, forKey: "allUsers")

I want to change a value for one user in that array of users:

var allUsers = defaults.objectForKey("allUsers") as! [String:NSMutableDictionary]

let changingUser = allUsers["userName"]! as NSMutableDictionary

Neither of these will work:

changingUser.setObject(3, forKey: "difficulty")
changingUser["difficulty"] = 3

with the error:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'

1
The objects returned from objectForKey will be immutable. You can't simply downcast an immutable dictionary to a mutable dictionary. You need to create a new NSMutableArray from the array returned from user defaults, modify that and then write it back.Paulw11
You could also type your allUsers dictionary initially, such as let allUsers: [String:NSMutableDictionary] = .... Your cast to NSMutableDictionary would be correct at that point.Wyatt

1 Answers

1
votes

You can't just cast a NSDictionary to a NSMutableDictionary. You can initialize one by passing in an immutable counterpart, but unfortunately that isn't a deep mutable structure.

However, you can cast it to a Swift Dictionary and assign it to a var:

var allUsers = defaults.objectForKey("allUsers") as? [String: [String: Int]] ?? [:]
allUsers2["userName"]?["difficulty"] = 3

But note that Swift dictionaries are value objects and have value semantics. That is, if you do this in steps like so:

var allUsers = defaults.objectForKey("allUsers") as? [String: [String: Int]] ?? [:]
changingUser = allUsers["userName"]
changingUser?["difficulty"] = 3 //mutates a copy

This will not work, since changingUser is a copy and while writing to it, does mutate it, it doesn't mutate the allUsers dictionary. So you have to either write the changed inner dict back into the outer dict, or do as I did above.