I have been through similar questions, but not able to solve my issue.
The issue is i have a call to API and i am storing the response in a NSDictionary, the response is a single value like RED or GREEN:
saveBlock:^( NSDictionary *data, NSError **err )
{
if (! *err)
{
if (data)
{
NSLog(#"KEY %# - VALUE %#",data.allKeys,data.allValues); //Error because i am performing .allKeys on type NSString
NSString *str = data; // error because i am assigning NSDictionary to string.
}
}
else
{
NSLog(#" error is : - %#",*err);
}
}];
Aren't these two error messages contradicting each other ? Anyone explanation about this issue. Thank you.
EDIT The first NSLog gives this error : *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString allKeys]: unrecognized selector sent to instance 0x170664b80'
(This error appears only at runtime and not when i type data.allKeys)
And the second NSLog gives this: Incompatible pointer type, initialising NSString* with an expression of type NSDictionary *
(This is shown after typing, i don't know what this type of error is called :D)
It is a standard practice to check your response type and error message before performing any operation, sort of defensive coding.
eg.
DLog(#"Object:%#,Error:%#",responseObject,error);
if (error != nil) {
DLog(#"Got error from API:%#",error);
return ;
}
if (!responseObject) {
DLog(#"Response object is not valid, returning...");
return;
}
if (![responseObject isKindOfClass:[NSDictionary class]]) {
DLog(#"Incorrect type of returned object, expecting NSDictionary, got:%#",[responseObject class]);
return;
}
Also I am pretty sure you are getting a NSString cause you don't get an error when assigning a NSDictionary to a NSString
Webservice response data 'data' should be NSDictionary, but in your case you are getting NSString. For NSString class, there is no allKeys method available, that is why you are getting crash. One thing is to validate for NSDictionary like.
if (data && [data isKindOfClass:[NSDictionary class]]) {
NSLog(#"KEY %# - VALUE %#",data.allKeys,data.allValues); //Error because i am performing .allKeys on type NSString
NSString *str = data; // error because i am assigning NSDictionary to string
}
Or remove NSLog
Related
I'm getting Json response with subArrays of dictionaries and I'm looking for particular value inside of one the subArrays. This is the subArray I care about:
<__NSArrayM 0x600000047680>(
{
value = "VeryImportanValue";
},
{
value = "someValue";
},
{
value = 0912131235235234;
}
)
I'm looking for the dictionary with the value of "VeryImportanValue". But as you can see you of the values are numeric and I check:
if ([[dict objectForKey:#"value"]isEqualToString:#"VeryImportanValue"])
I get this error:
-[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance
But switch the if statement to fix the error above:
if ([[[dict objectForKey:#"value"] stringValue] isEqualToString:#"VeryImportanValue"])
I get this error:
-[__NSCFString stringValue]: unrecognized selector sent to instance
How can I check the value of the dictionary without getting any of this errors regarless if is string or numeric value?
I'll really appreciate your help.
You could create a method that turns the unknown object into a string:
- (NSString *)stringForStringOrNumber:(id)object
{
NSString *result = nil;
if ([object isKindOfClass:[NSString class]]) {
result = object;
} else if ([object isKindOfClass:[NSNumber class]]) {
result = [object stringValue];
} else {
result = #"I can't guess";
}
return result;
}
Before you do isEqualToString, you should first check the value type of your dictionary.
if(dict[#"value"]isKindOfClass==[NSString class]) //value is string
I am getting an error with the following code when some json is null even though I am trying to check that first:
Edit: Preceding Code:
NSData* data = [NSData dataWithContentsOfURL: kItemsURL];
//previous line grabed data from api.
if (data) {
[self performSelectorOnMainThread:#selector(fetchData:) withObject:data waitUntilDone:YES];
}
- (void)fetchData:(NSData *)jsonFeed {
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:jsonFeed options:kNilOptions error:&error];
//Original code provided
if (![[json objectForKey:#"items"] isKindOfClass:[NSNull class]]) {
NSLog(#"got here");
NSLog(#"json%#",json);
latestItems = [[json objectForKey:#"items"]mutableCopy];
}
Is there a better way to check Json is not null?
Here is error output:
2016-05-03 13:05:43.820 testApp[407:60b] got here
2016-05-03 13:05:43.821 testApp[407:60b] json{
items = "<null>";
}
NSNull mutableCopyWithZone:]: unrecognized selector sent to instance 0x3ac26a70
2016-05-03 13:05:43.825 ChallengeU[407:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSNull mutableCopyWithZone:]: unrecognized selector sent to instance 0x3ac26a70'
if (![json[#"items"] isEqual:[NSNull null]]) {
//do your stuff in here
}
I don't know what's wrong with your code, but the easiest way to check for a JSON null value if you are sure that json is a dictionary is:
if (json [#"items"] != [NSNull null]) { ... }
[NSNull null] always returns the same instance of NSNull. There is never more than one instance of NSNull, so you can actually use pointer comparison to check whether an object is an NSNull instance.
if (json && [json isKindOfClass:[NSDictionary class]]) {
//your code here
} else {
//invalid json
}
if ([json objectForKey:#"items"] != nil) {
NSLog(#"got here");
NSLog(#"json%#",json);
latestItems = [[json objectForKey:#"items"]mutableCopy];
}
NULL or nil is not a class, but a convention. The memory adress 0 is the point where a cpu starts to execute code during cold start. Therefore no object can have this address in memory.
By the book should the json not have the key #"items" if the value of #"items" is NULL. The missing key indicates a NULL value.
I'm calling the following code on a number of JSON dictionaries within another dictionary (so in this case, NSDictionary objects with another NSDictionary.
-(NSString *)getAllDictionaryValues:(NSDictionary *)dict
{
NSString *output=[NSString stringWithFormat:#""];
for(NSString *key in [dict allKeys])
{
output = [NSString stringWithFormat:#"%#\n%#: %#",output, key, [dict objectForKey:key]];
}
return output;
}
When I run this code, however, I get
2014-03-30 01:27:35.565 WebServiceTest[48606:60b] -[__NSCFString allKeys]: unrecognized selector sent to instance 0x9270230
What is wrong about my call to allKeys?
Like when you sending message to this function it may be declare your code that dict is an NSDicationay object (when you call this function) but it not an dictionary may be an array of String or etc that why you getting the exception.
-(NSString *)getAllDictionaryValues:(NSDictionary *)dict
So first check your dict like
if([dict isKindOfClass:[NSArray class]]){
//is an array
}else if([dict isKindOfClass:[NSDictionary class]]){
//is an dictionary
}else if([dict isKindOfClass:[NSString class]]){
//is an string
}else{
//or its something else
}
May be you are inputting a string rather than a dictionary object in the calling method
That's obvious. As log said, you tried to call allKeys method on __NSCFString instance. It means that you sent NSString instead of NSDictionary to getAllDictionaryValues: method.
It means the dict object is NSString type. You can check the object like this:
if([dict isKindOfClass:[NSDictionary class]]) {
// dict is NSDictionary type of object
} else if([dict isKindOfClass:[NSString class]]) {
// dict is string type of object.
}
So I am really new at developing for iOS, and I've been doing my best, to search for an answer, to debug it and anything I could come up with.
Though, I haven't been able to find a solution to the issue.
I've been trying to fetch an external JSON document, which works fine, but when it comes to parsing it, it buggers up.
First of all, this is the error message I'm getting, the whole lot of it.
2013-01-31 22:40:19.261 demodh[6205:c07] View Loaded
2013-01-31 22:40:19.479 demodh[6205:c07] -[__NSCFStringcountByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7554f90
2013-01-31 22:40:19.480 demodh[6205:c07] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString countByEnumeratingWithState:objects:count:]: unrecognized selector sent to instance 0x7554f90'
*** First throw call stack:
(0x1c93012 0x10d0e7e 0x1d1e4bd 0x1c82bbc 0x1c8294e 0x28d3 0xbd6589 0xbd4652 0xbd589a 0xbd460d 0xbd4785 0xb21a68 0x4615911 0x4614bb3 0x4652cda 0x1c358fd 0x465335c 0x46532d5 0x453d250 0x1c16f3f 0x1c1696f 0x1c39734 0x1c38f44 0x1c38e1b 0x1bed7e3 0x1bed668 0x14ffc 0x1d6d 0x1c95 0x1)
libc++abi.dylib: terminate called throwing an exception
(lldb)
And this is the code I'm using at the moment:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allDataDictionary = [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
for(NSDictionary *dict in allDataDictionary)
{
if (![allDataDictionary isKindOfClass:[NSDictionary class]])
{
NSLog(#"2Unable to process temp array because it's an instance of %#", [allDataDictionary class]);
}
else
{
for(NSDictionary *deal in dict)
{
if (![deal isKindOfClass:[NSDictionary class]])
{
NSLog(#"Unable to process temp array because it's an instance of %#", [deal class]);
}
else
{
NSString *title = [deal objectForKey:#"title"];
NSLog(title);
}
}
}
}
}
And the JSON I'm loading is: Link
I hope you're able to assist me in finding a solution.
The problem is you're fast-enumerating a NSDictionary and expecting to get its values, when in fact you'll get its keys. When you try to fast-enumerate an NSString you get the assertion you're seeing. You probably wanted this:
for(NSObject *key in allDataDictionary) {
NSDictionary *dict = allDataDictionary[key];
...
for (NSObject *dealKey in dict) {
NSDictionary *deal = dict[dealKey];
}
...
Alternatively, if you really want to enumerate the values and don't need the keys:
for(NSDictionary *dict in [allDataDictionary allValues]) {
...
I intend to convert the NSDictionary* object in iOS SDK to NSString*.
Lets say my NSDictionary object has following key value pairs:
{"aps":{"badge":9, "alert":"hello"}} (notice that value itself is a NSDictionary object)
and I want it to convert into a hash map with key value pair as {"aps":"badge:9, alert:hello"} (notice value is just a string).
I am able to print the value in NsDictionary using the following code:
NSDictionary *userInfo; //it is passed as an argument and contains the string I mentioned above
for (id key in userInfo)
{
NSString* value = [userInfo valueForKey:key];
funct( [value UTF9String]; // my function
}
But i am not able to call any NSString method on value object like UTT8String. It gives me error "Terminating app due to uncaught exception NSInvalidArgumentException: reason [_NSCFDictionary UTF8String]: unrecognised selector sent to instance
You are going to have to recursively process the dictionary structure, here is an example that you should be able to adapt:
-(void)processParsedObject:(id)object{
[self processParsedObject:object depth:0 parent:nil];
}
-(void)processParsedObject:(id)object depth:(int)depth parent:(id)parent{
if([object isKindOfClass:[NSDictionary class]]){
for(NSString * key in [object allKeys]){
id child = [object objectForKey:key];
[self processParsedObject:child depth:depth+1 parent:object];
}
}else if([object isKindOfClass:[NSArray class]]){
for(id child in object){
[self processParsedObject:child depth:depth+1 parent:object];
}
}
else{
//This object is not a container you might be interested in it's value
NSLog(#"Node: %# depth: %d",[object description],depth);
}
}
You need to apply that loop to each child, not the main dictionary. You said yourself you have a dictionary in a dictionary:
for(id key in userInfo)
{
NSDictionary *subDict = [userInfo valueForKey:key];
for(id subKey in subDict)
{
NSString* value = [subDict valueForKey:subKey];
}
}
This loop assumes you have the entire dictionary in the first level, otherwise you will need to use danielbeard's recursive method.
I found the easiest way out. calling the description method on the NSDictionary object gives me what I needed exactly. Stupid to have missed it on first go.