3

I am trying to implement In App Purchases, and I am tracking which purchases a user has purchased via NSUserDefaults. 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 var instead of a let and is an NSMutableDictionary. Sometimes it does work, but most of the time it doesn't. I get a few warnings about declaring my variables with let instead of var, 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' 

Code:

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 \(purchase.id()) to \(value)") var key = purchase.id() // WARNING: should be declared with let because not mutated purchases[key] = value // CRASH HERE defaults.setObject(purchases, forKey:PURCHASES_KEY) defaults.synchronize() } } 
2
  • @ozgur Since I am setting a key value pair, it does have to be of NSMutableDictionary type. Regular old AnyObject type won't let me do that as far as I know. Commented May 13, 2016 at 23:22
  • @ozgur Make your comment an answer. It seems to have worked, but I have no idea why. Commented May 13, 2016 at 23:40

1 Answer 1

3

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/immutability in collection types.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.