mutating method sent to immutable object' in nsmutablearray - ios

I want to remove objects from NSmutableArray can one tell me the Best way to remove from NSMutableArray
.h
#property(nonatomic,retain)NSMutableArray *arr_property;
.m
_arr_property=[[NSMutableArray alloc]init];
MTPop *lplv = [[MTPop alloc] initWithTitle:SelectProperty(APP_SHARE.language)
options:[_arr_property valueForKeyPath:#"property_list.property_type_name"]
handler:^(NSInteger anIndex) {
txt_Property.text=[[_arr_property valueForKeyPath:#"property_list.property_type_name"] objectAtIndex:anIndex];
NSLog(#"index number %ld",(long)anIndex);
remove object--->>>
NSLog(#"index number %#",[_arr_property valueForKey:#"property_list"]);
[[_arr_property valueForKeyPath:#"property_list.property_type_name"] removeObjectAtIndex:anIndex]; ////hear the app is crashing
app is crashing error iam getting is
2015-06-09 13:21:31.104 Estater[2170:62264] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'

Think about your code:
_arr_property=[[NSMutableArray alloc]init];
You now have an empty NSMutableArray. It has no elements.
[... removeObjectAtIndex:0];
What did we just say? The array has no elements. It has no element 0 - to have an element 0 it would need to have one element at least, but it doesn't. There is nothing to remove.
[_arr_property valueForKeyPath:#"property_list.property_type_name"]
That part is the weirdest, but let's carry on. When called on an array, valueForKeyPath: results in an NSArray - not an NSMutableArray. So this gives you an empty NSArray. But you cannot say removeObjectAtIndex: to an NSArray, even if it empty - it is not mutable. That's the crash you are experiencing.

The real error is that you are calling removeObject on an element of your NSMutableArray:
[-->[_arr_property valueForKeyPath:#"property_list.property_type_name"]<-- removeObjectAtIndex:0];
The array looks empty, but if filled with something, to remove the first element you should do instead:
[_arr_property removeObjectAtIndex:0];

Firstly, you cannot work with NSMutableArray for key value coding it does not support. You must better use NSMutableDictionary for it.
As dictionaries store objects based on a key, whereas arrays store objects based on an index.
You can use NSMutableDictionary like this:
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:something forKey:#"Some Key"];
// ... and later ...
id something = [dict objectForKey:#"Some Key"];
Secondly, valueForKeyPath: returns a value not array and valueForKey: returns array of value for the key and also that array is not mutable.
Edit:
Thirdly, after researching more on valueForKeyPath:, found its use in collection operation and syntax for using is. So, do it by changing
[_arr_property valueForKeyPath:#"property_list.property_type_name"]
To
[_arr_property valueForKeyPath:#"#property_list.property_type_name"]

Related

Making a mutable array from plist

I'm trying to make an NSArray from a key in save data and make it mutable. Here's what I have so far:
NSMutableArray *availableThemes = [[[saveData valueForKey:#"availableThemes"] array] mutableCopy];
If I'm correct, sending array makes this object returned by availableThemes an array with the contents of the object, and then mutableCopy makes this array a NSMutableArray. Sadly, and obviously, I'm not. I get this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray array]: unrecognized selector sent to instance 0x786c7430'
Here, I thought, sending array would turn this data into a NSArray. Instead, it causes a complier error. I know I did something stupidly wrong. Question is, what did I do?
You are calling the class method array on an instance of NSArray.
NSMutableArray *availableThemes = [[[saveData valueForKey:#"availableThemes"] array] mutableCopy];
From your crash log it is clear that the availableThemes key returns an NSArray object, so change your code to:
NSMutableArray *availableThemes = [[saveData valueForKey:#"availableThemes"] mutableCopy];

Updating the Value for a Key in an NSMutableOrderedSet object

I have the following statements
[[myListSet objectAtIndex:sender.tag] setValue:#"1" forKey:#"STATUS"];
where myListSet is defined as
NSMutableOrderedSet *myListSet;
myListSet is a list of dictionary entries, each with 6 key-value pairs, with one of the Keys being STATUS.
I thought I could update the values in one of the dictionaries using the above line. It worked in simulator, but not on my iPhone.
The error I am getting is
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
I guess my thought on updating the entry is incorrect. Any ideas on how to update a value for one of the keys for one of the dictionary entries in this set?
NSMutableOrderedSet allows you to modify its direct children. The error you are seeing arises because your NSMutableOrderedSet contains NSDictionary objects and not NSMutableDictionary objects.
In order to modify the sub-dictionaries, you will need them to be NSMutableDictionary objects. You could do this by:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:[myListSet objectAtIndex:sender.tag]];
dict[#"STATUS"] = #"1";
[myListSet replaceObjectAtIndex:sender.tag withObject:dict];
You should be aware that anything that was holding a reference to the original immutable dictionary will still be holding that dictionary and not your modified dictionary.
setValue:forKey makes use of key-value coding which lets you set an object's properties. NSMutableOrderedSet doesn't come with a "STATUS" property out of the box.
You want to use setObject:forKey instead
I believe your data structure is a set of NSDictionary. Your set is mutable but the dictionary within it is immutable.
If you have access to that dictionary then change NSDictionary to NSMutableDictionary and this will work. If not then
NSDictionary *myDictionary = [myListSet objectAtIndex:sender.tag];
NSDictionary *myMutableDictionary = [myDictionary mutableCopy];
[myMutableDictionary setValue:#"1" forKey:#"STATUS"];
[myListSet setObject:myMutableDictionary atIndex:sender.tag]

App Crashing: Mutating method sent to immutable object

I am trying to add an object to an NSMutableArray. Initially I assign some response data to the array, and can display it in a table view. After loading more data, it seems to be crashing when trying to add the new information to my original array.
I am using AFNetworking for this:
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if(!_myArray){
_myArray = [responseObject objectForKey:#"data"];
}
else{
[_myArray addObject:[responseObject objectForKey:#"data"]];
}
[self.tableView reloadData];
}
The error I am getting is as follows
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
Can anybody help out with this?
The object you're retrieving from the responseObject dictionary is most likely not an NSMutableArray, but an (immutable) NSArray. You have to create a mutable copy to be able to change it:
//...
if (!_myArray) {
_myArray = [[responseObject objectForKey:#"data"] mutableCopy];
}
//...
It sounds like AFNetworking generates immutable objects. You should call -mutableCopy instead of just assigning the result of -objectForKey: directly.
Also are you really intending to have a bunch of nested arrays? It seems like it would make more sense if you added the contents of the response array, rather than the array itself.
You need to make the copy of your array. After that you have to modify that array using, [NSMutableArray arrayWithArray: ]
Your array is must be mutable array
Use NSMutablearray instead NSArray

Empty NSMutableArray read from plist becomes immutable object

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'"
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.
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.
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];

app is crashing on second run through of loop with nsnull count

I have a loop that works fine the first time through but the second time through the loop I get:
-[NSNull count]: unrecognized selector sent to instance 0x3a094a70
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull count]: unrecognized selector sent to instance 0x3a094a70'
Here is the part in my code where I know it is crashing (the last line):
...
NSLog(#"dict::%#",dictForPost);
// collect the photo urls in an array
photosInDict = [NSArray array];
// photos is an array of dictionaries in the dictionary
photosInDict = dictForPost[#"photos"];
if (photosInDict.count) {
....
I know that when photosInDict doesnt have pictures in the dic it crashes but I dont get why since I initiated the array above it.
photosInDict = dictForPost[#"photos"]
replaces the object previously allocated and stored in photosInDict.
Therefore it does not make sense to allocate the array before. Just
NSArray * photosInDict = dictForPost[#"photos"];
and then check
if ([photosInDict isKindOfClass:[NSArray class]]) {
// Yes, it is an array. Do something with it.
if ([photosInDict count]) {
...
}
}
The result of dictForPost[#"photos"]; is giving you an NSNull object, not an array.
One option would be this:
NSLog(#"dict::%#",dictForPost);
// collect the photo urls in an array
// photos is an array of dictionaries in the dictionary
photosInDict = dictForPost[#"photos"];
if ([photosInDict isKindOfClass:[NSArray class]] && photosInDict.count) {
The line:
photosInDict = [NSArray array];
is pointless and should be removed.
You initialize photosInDict with an empty array, but then you overwrite it with the dictionary's value for "photos", which just happen to be NSNull. You need to check why your dictionary does not have an array for that key.
If the value can be NSNull depending on the situation, you must check whether it is an array or not before trying to count or taking some other action.

Resources