Reputation: 889
Write an empty NSMutableArray to disk, then read it back, it becomes an immutable object.
But, if the NSMutableArray is not empty, it won't. How to explain that?
here are the codes:
NSMutableArray *testItems1 = [NSMutableArray array];
NSMutableDictionary *testList1 = [NSMutableDictionary dictionaryWithObjectsAndKeys:testItems1, @"list_items", @"list1", @"list_name", nil];
NSMutableArray *testItems2 = [NSMutableArray arrayWithObjects:@"item11", @"item22", nil];
NSMutableDictionary *testList2 = [NSMutableDictionary dictionaryWithObjectsAndKeys:testItems2, @"list_items", @"list2", @"list_name", nil];
NSMutableArray *testLists = [NSMutableArray arrayWithObjects:testList1, testList2, nil];
[testLists writeToFile:@"/tmp/testLists" atomically:YES];
NSMutableArray *testReadLists = [NSMutableArray array];
[testReadLists setArray:[NSArray arrayWithContentsOfFile:@"/tmp/testLists"]];
NSMutableDictionary *testReadList = [testReadLists objectAtIndex:0];
NSMutableArray *testReadItems = [testReadList objectForKey:@"list_items"];
[testReadItems addObject:@"item3"]; // Crashes here: "*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'"
Upvotes: 0
Views: 231
Reputation: 125017
Objects read straight from property lists are always immutable. You might create a mutable object from them, but the objects themselves are immutable. These lines are the problem:
NSMutableDictionary *testReadList = [testReadLists objectAtIndex:0];
NSMutableArray *testReadItems = [testReadList objectForKey:@"list_items"];
testReadList
is the first object in the mutable array testReadLists
, but that object itself is still immutable despite the fact that the declared type of testReadList
is NSMutable*
. Likewise, the object you get back from the objectForKey:
call is an instance of NSArray
even though you're assigning it to testReadItems
, which is declared as NSMutableArray*
. You can avoid the problem by simply making a mutable copy before you add new items:
NSMutableArray *testReadItems = [[testReadList objectForKey:@"list_items"] mutableCopy];
Upvotes: 0
Reputation: 564
Haven't tested this myself, but you probably want to first read the plist into an NSData, and then get the actual array by doing +[NSPropertyListSerialization propertyListWithData:options:format:error:]
, specifying NSPropertyListMutableContainers
in the options argument (apple doc here)
Note this should give you a full hierarchy of mutable containers (an NSMutableArray containing NSMutableDictionaries, and so on). If all you want is an NSMutableArray at one particular level in the hierarchy, then the other posted solution/comments would probably be a more appropriate solution.
Upvotes: 1
Reputation: 318924
These two lines of code:
NSMutableArray *testReadLists = [NSMutableArray array];
[testReadLists setArray:[NSArray arrayWithContentsOfFile:@"/tmp/testLists"]];
give you a mutable array of immutable objects. You can add and remove objects from testReadLists
but everything you get from this array (originally loaded from the plist) will be immutable.
Update - I was about to post info about the solution but the answer by Vivek describes what I was going to say.
Upvotes: 3