Mutating method sent to immutable object - ios

I'm using JSONKit to parse a JSON string returned from my server in my iPhone application. Part of the server response is a couple of Base64 encoded images that I want to decode into actual images and add to the object that the parser creates. The problem is I can't seem to figure out what kind of class the parser returns, and thus what kind of methods that can be used to interact with the object. I've searched the JSONKit documentation for answers to my question, but haven't found it.
decodedData = [[request responseString] objectFromJSONString];
int i = 0;
[Base64 initialize];
for (NSString *base64String in [decodedData valueForKey:#"base64String"]) {
UIImage *image = [UIImage imageWithData:[Base64 decode:base64String]];
[decodedData setValue:image forKey:#"image"];
i++;
}
This code is placed in a method that gets called when the request has successfully finished and the response is returned in [request responseString] (the JSON). The decodedData object's class is defined in the header file. No matter what I declare it as (either NSArray, NSMutableArray, NSDictionary, or NSMutableDictionary) I get the same error when the code is run (it compiles just fine), which is:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '*** -[JKDictionary setObject:forKey:]: mutating method sent to immutable object'
Can anybody tell me what kind of class the object is, and what I should do to add the Base64-decoded image to the object?
I'm pretty new to Objective-C, so bear over with me. Thanks.

You're trying to mutate the immutable JKDictionary (itself a proxy for an immutable NSDictionary object).
The documentation you linked to specifies an instance method on NSString named - (id)mutableObjectFromJSONString;, this will give you a mutable dictionary object that you can play with if you so desire.

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]

NSDictionary (__NSDictionaryI) isMemberOfClass: isKindOfCLass: difference

I understand the difference between isKindOfClass: and isMemberOfClass: but I came across something I do not understand:
-(UIImage *)doSomething:(id)item
{
UIImage *image;
if ([item isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = item;
NSData *data = [dictionary objectForKey:#"image"];
image = [[UIImage alloc] initWithData:data];
} else { // if item is UIImage
image = item;
}
return image;
}
If I am using isKindOfClass in this context everything works as expected. If I use isMemberOfClass I get the following crash asking for the size of the image later:
-[__NSDictionaryI size]: unrecognized selector sent to instance 0x123456
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI size]: unrecognized selector sent to instance 0x123456'
I read other posts like this one but I couldn't find anything that would come closer.
Yes they are different and their difference is documented. Using isKindOfClass: will return YES for subclasses whereas isMemberOfClass: won't. Since NSDictionary is a class cluster (uses private subclasses internally) will get different results when using the two (because the instance would be a private subclass (in your case __NSDictionaryI).
When using isMemberOfClass:, this is what happens in your case:
The argument item is a private dictionary subclass
Evaluating isMemberOfClass: returns NO
The dictionary is assigned to a UIImage variable
The UIImage variable is returned (but it really contains a dictionary)
You try and use that "image" and when the system asks for the image size, the dictionary doesn't respond to size and throws an exception.

Exception on NSData to NSString?

I'm trying to convert NSData to NSString, and I'm getting a SIGABRT on this command
NSString* newStr = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
It appears the exception is NSInvalidArgumentException, reason: unrecognized selector sent to instance.
I inspect the NSData object in a breakpoint and it pops up with expected data. Why on earth would a simple data conversion like this go so wrong? Any thoughts?
You guys pointed me in the winning direction by questioning type of object ... I was extracting it from a dictionary and assumed it was an NSData object, but in reality it was already an NSString. Ugh. Thanks a lot!

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

Resources