Aderis Aderis - 1 year ago 75
Swift Question

Swift mutable dictionary being treated as immutable

I am trying to implement In App Purchases, and I am tracking which purchases a user has purchased via

. I have a function that sets the values of each purchase, but when it runs, I get an error saying that I am mutating the dictionary of purchase values even though the dictionary is declared with a
instead of a
and is an
. Sometimes it does work, but most of the time it doesn't. I get a few warnings about declaring my variables with
instead of
, but I ignore them to give my variables maximum mutability. Why does this not work?

The error I get is:

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


static func setPurchased(purchase:PurchaseID, value:Bool)
let defaults = NSUserDefaults.standardUserDefaults()

if (defaults.objectForKey(PURCHASES_KEY) == nil)
initializePurchases() // go set some initial values

if var purchases = (defaults.objectForKey(PURCHASES_KEY) as? NSMutableDictionary) // WARNING: should be declared with let because not mutated
print("setting purchase \( to \(value)")
var key = // WARNING: should be declared with let because not mutated

purchases[key] = value // CRASH HERE
defaults.setObject(purchases, forKey:PURCHASES_KEY)

Answer Source

This is not the right way of converting an immutable dictionary into its mutable counterpart.

var already ensures that whatever is returned from defaults.objectForKey(PURCHASES_KEY) will be copied as a mutable type so all you need is specify the type of the mutable object which in our case can safely be Dictionary<String: AnyObject> if you are sure all keys are String type:

if var purchases = defaults.objectForKey(PURCHASES_KEY) as? Dictionary<String: AnyObject> {
  purchases[key] = value

Please see this SO question for more information about mutability/immutable in collection types.