NSDictionary (__NSDictionaryI) isMemberOfClass: isKindOfCLass: difference - ios

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.

Related

Fatal error when setting UIImageView in objective c

Hello i have a UIImageview and trying to set the image which was previously saved in a NSArray and then the NSArray is saved into an NSMutableDictionary. Here is the error and the code. Any help appreciated.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString _isSymbolImage]: unrecognized selector sent to instance 0x100e14318'
terminating with uncaught exception of type NSException
myAppDelegate *appDelegate = (myAppDelegate *)[UIApplication sharedApplication].delegate;
NSMutableArray *allKeys = [[appDelegate.localDataForIngestAndErrorVideos allKeys] mutableCopy];
for (NSString *key in allKeys) {
NSArray *object = (NSArray*)[appDelegate.localDataForIngestAndErrorVideos objectForKey:key];
NSLog(#"id object ingest: %#",[object objectAtIndex:0]);
if ( [cell.Model.ContentItem.videoUploadStatus isEqualToString:#"ingest"])
{
cell.Model.ContentItem.mediaVideoUriHls = (NSURL*)[object objectAtIndex:2];
UIImage *tempImage = [[UIImage alloc]init];
tempImage = [object objectAtIndex:1];
[cell.mediaImageView setImage:tempImage]; <=== here crashes
}
}
The error [__NSCFConstantString _isSymbolImage]: unrecognized selector sent to instance is saying this:
Let's translate first: __NSCFConstantString is a inner (optimized) class for NSString, so just consider it as NSString
So you have NSString instance and you try to call _isSymbolImage method on it. That method is hidden, it's an under the hood call from iOS SDK.
But that method doesn't exists on NSString, it doesn't know it, hence the error you are getting.
Seeing the crash line:
[cell.mediaImageView setImage:tempImage];
The inner method called makes sense, you are treating tempImage as it were an UIImage.
So [object objectAtIndex:1] is a NSString not a UIImage.
Now, I'd suggest to use custom model for your NSDictionary appDelegate.localDataForIngestAndErrorVideos. It's better than handling NSArray/NSDictionary without knowing what's inside it each time.
You could also add to it methods/compute properties like -(NSURL)ingestURL, etc to make your code easier and more readable.
Side note:
UIImage *tempImage = [[UIImage alloc]init];
tempImage = [object objectAtIndex:1];
The alloc/init is useless, since you are setting the value. You are doing an alloc/init for nothing, since you are ignoring it just after.

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.

__NSCFConstantString objectForKey unrecognized selector sent to instance error

I basically get this error
'NSInvalidArgumentException', reason: '-[__NSCFConstantString objectForKey:]: unrecognized selector sent to instance 0x581f0'
on my program. I think it refers to this call I make,
if (data != nil) {
if([data objectForKey:#"username"]){
// NSArray *check= [[NSArray alloc]init];
//check=[data allValues];
[dict setObject:[data allValues] forKey:#"args"];
}else{
[dict setObject:[NSArray arrayWithObject:data] forKey:#"args"];
}
at the setObject:[data allValues]. I don't know why it gives that error but data is an NSDictionary and I'm getting all the values and placing it in an array.
Is the error happening here:
if([data objectForKey:#"username"]){
I assume so, as that is the only place objectForKey seems to be called. You are calling it on a variable called 'data', which i'm guessing simply is not a dictionary. You should NSLog its type to see.

NSArray SIGABRT

NSString* year = [self.years objectAtIndex:[indexPath section]];
//get algorithms for that year
NSArray* algorithmSection = [self.algorithmNames objectForKey:year];
NSLog(#"%#", indexPath);
//get specific algorithm based on that row
cell.textLabel.text = [algorithmSection objectAtIndex:indexPath.row];
return cell;
For whatever reason, when I compile this, I get a SIGABRT error. It happens on the
cell.textLabel.text
line. Error:
2011-08-29 19:26:21.273 xxxxxxxxxxx[1431:b303] 2 indexes [0, 0]
2011-08-29 19:26:21.274 xxxxxxxxxxxxx[1431:b303] -[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x4ba2370
2011-08-29 19:26:21.277 xxxxxxxxx[1431:b303] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x4ba2370'
terminate called throwing an exception
Your algorithmSection variable, which your code expects to be an NSArray, is actually an NSDictionary, which does not respond to the selector -objectAtIndex:.
As lemnar and mjisawai said, you are actually dealing with an NSDictionary.
The way to fix this depends on the context of your app.
If you happen to receive either, NSArrays or NSDictionary objects then you may determine this by texting the object's class.
i.e.
if ([algorithmSection isKindOfClass:[NSArray class]]) {
...
} else if ([algorithmSection isKindOfClass:[NSDictionary class]]) {
...
}
Could the object at key "year" in your algorithmSections dictionary be a dictionary instead of an array? That's what it looks like is happening here.

Mutating method sent to immutable object

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.

Resources