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]
Related
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];
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"]
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
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];
I have declared an NSMutableArray *arrAllRecordsM and am trying to add NSMutableDictionary *dicRecordM to it using addObject. The dicRecordM gets added to arrAllRecordsM but on doing [dicRecordM removeAllObjects] it sets to nil in arrAllRecordsM. Below is the code, please help me fix it.
self.arrAllRecordsM = [NSMutableArray array];
self.dicRecordM = [NSMutableDictionary dictionary];
// Some Method
[self.dicRecordM setObject:#"Test" forKey:#"ADDRESS"];
[self.arrAllRecordsM addObject:self.dicRecordM];
// Value: Test
NSLog(#"Value: %#", [[self.arrAllRecordsM objectAtIndex:0] valueForKey:#"ADDRESS"]);
[self.dicRecordM removeAllObjects];
// Value: null
NSLog(#"Value: %#", [[self.arrAllRecordsM objectAtIndex:0] valueForKey:#"ADDRESS"]);
Adding an object to an NSMutableArray just stores a pointer (or "strong reference")
to the object into the array. Therefore
[self.arrAllRecordsM objectAtIndex:0]
and
self.dicRecordM
are two pointers to the same object. If your remove all key/value pairs from self.dicRecordM then [self.arrAllRecordsM objectAtIndex:0] still points to the same
(now empty) dictionary. That is the reason why
[[self.arrAllRecordsM objectAtIndex:0] valueForKey:#"ADDRESS"]
returns nil.
If you want an independent copy of the dictionary in the array, use
[self.arrAllRecordsM addObject:[self.dicRecordM copy]];
copy can be used on many classes, such as NSDictionary, NSArray and NSString
and their mutable variants, to get a "functionally independent object". Formally, it is available for all classes conforming to the NSCopying protocol.
This is expected behavior.
You removed all the objects from the dictionary by calling removeAllObjects, then tried to retrieve an object from it and rightfully getting nil, since it doesn't exist in the dictionay anymore (you removed it).
What's maybe unclear to you is that NSArray doesn't copy the element you add to it, instead it just holds a strong reference.
So both dicRecordM and arrAllRecordsM are holding a reference to the same object, hence any modification to it (in this case removeAllObjects) will affect the same dictionary.
Incidentally, you shouldn't use valueForKey: for accessing the dictionary's entries. Use objectForKey: or the shorter subscripted syntax. For instance
self.arrAllRecordsM[0][#"ADDRESS"]
You can read this answer Difference between objectForKey and valueForKey? as a reference, but the main problem is that valueForKey: can behave very differently from objectForKey: in case the key contains special KVC characters, such as # or ..