1

I can't figure out what is causing this. Basically, a few different 'tasks' are colliding with each other in my app. When i press a button, it runs this code just fine:

PalAppDelegate *dataCenter = (PalAppDelegate *)[[UIApplication sharedApplication] delegate];




[dataCenter.colourPalettesContainer addObject:[NSNumber numberWithInt:5]];

It can do this as many times as i like. But when i perform another task (and theres a few which cause this to happen), which involves this code for example:

PalAppDelegate *dataCenter = (PalAppDelegate *)[[UIApplication sharedApplication] delegate];

[dataCenter.colourPalettesContainer removeObjectAtIndex:touchDownID];

NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:dataCenter.colourPalettesContainer forKey:@"container"];
[prefs synchronize];

and then:

dataCenter.colourPalettesContainer = [prefs objectForKey:@"container"];

When i run the first code again after this, it causes a crash with the "mutating method sent to immutable object" error. How can i stop this?

EDIT: So i've found out the problem from some answers below. Does anybody have a different method of doing this which they'd suggest?

Andrew
  • 15,935
  • 28
  • 121
  • 203
  • Your code is too deeply nested for humans to understand easily. I suggest you break your addObject statement into 5 or 10 sub-statements. Then if something breaks, you'll have a chance of figuring out where it is. – Rayfleck Apr 19 '11 at 01:39
  • It only broke since i added the saving to preferences line in. It's not related to my deeply nested Array. I'll remove some of the parts from that to make it easier to digest. – Andrew Apr 19 '11 at 01:41
  • You say "when I run the first code again after this, it crashes" - meaning somewhere in the nested array, right? So the problem is you don't know where in all of that assigning the problem is. I have found through much painful experience that highly complex statements like that don't save you any compile or performance time, don't make the code easier to maintain or debug, and so are not worth the time to construct them in the first place. I'm not criticising, just offering some friendly advice. – Rayfleck Apr 19 '11 at 01:49
  • The answers don't make much sense, frankly. Post the backtrace of the crash. – bbum Apr 19 '11 at 03:37
  • My answer made more sense before Andrew edited his question. He's adding a bunch of mutable collections to NSUserDefaults, then trying to call mutating method on an object he fetches back. The question as its currently written doesn't make that clear, but the original did. – Sherm Pendley Apr 19 '11 at 15:26

3 Answers3

6

NSUserDefaults returns an immutable array. You need to make a mutable copy of it when you load it back up:

NSMutableArray *mutableArray = [[prefs objectForKey:@"container"] mutableCopy];
dataCenter.colourPalettesContainer = mutableArray;
[mutableArray release];

You might also have to do some manipulation inside of the array since you were storing NSMutableArrays within it.

McCygnus
  • 4,187
  • 6
  • 34
  • 30
  • I think you're right, as implementing that code is causing some very strange behaviour inside my app. Any ideas what sort of manipulation i'd need to do inside the array though? – Andrew Apr 19 '11 at 01:52
  • I'd switch it up so that you're only holding immutable objects to make it simpler. For the arrays, hold them as NSArrays instead of NSMutableArrays. Then when you need to change the contents, pull it out, make a mutable copy, add/remove items, and then add it back to the main array. I'd also probably make colourPalettesContainer a dictionary instead of an array. That way you're documenting what the value is with your key. You also replace based on the key then and don't have to worry about the index. Order didn't look to matter for this case. – McCygnus Apr 19 '11 at 02:44
  • +1 for you, as it saved my time as well, i don't know why that problem occured, even my array was a mutable array.......... – Sabby May 19 '11 at 10:33
2

NSUserDefaults always returns immutable objects, even if what you stored was mutable. To work around this, you need to make a mutable copy. Since -mutableCopy returns an object that the caller owns, it needs to be (auto)released:

dataCenter.colourPalettesContainer = [[[prefs objectForKey:@"container"] mutableCopy] autorelease];

(Edit) I posted some -mutableDeepCopy NSArray & NSDictionary methods a while back, in response to another question. If your problem involves deeper nesting of collections, and you need them all to be mutable, this may help.

Community
  • 1
  • 1
Sherm Pendley
  • 13,556
  • 3
  • 45
  • 57
0

TO REMOVE AN OBJECT FROM PARTICULAR INDEX OF AN ARRAY. (Swift 3.0)

let fullArray : NSArray = Userdefaults().value(forKey: "YOUR_ARRAY_STRING") as! NSArray
var mutableArray : [AnyObject] = fullArray as [AnyObject]
mutableArray.remove(at: INDEX_TO_REMOVE) //Eg: mutableArray.remove(at: 0)
mutableArray.append(ARRAY_TO_APPEND)
Ram Madhavan
  • 2,362
  • 1
  • 17
  • 20