JSON request error [closed] - objective-c

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm experimenting with JSON for the first time in Objective-C.
Here's the code for my Terminal Application:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://itunes.apple.com/search?term=harry&country=us"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *jsonParsingError = nil;
NSArray *publicTimeline = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
NSDictionary *list;
for(int i=0; i<[publicTimeline count];i++)
{
list = [publicTimeline objectAtIndex:i];
NSLog(#"Statuses: %#", [list objectForKey:#"trackName"]);
}
}
return 0;
}
Here's the error I'm getting:
2013-09-11 20:58:55.524 Tweets[7291:303] -[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x100391d60
2013-09-11 20:58:55.526 Tweets[7291:303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary objectAtIndex:]: unrecognized selector sent to instance 0x100391d60'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff91688b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff8bf8a3f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff9171f40a -[NSObject(NSObject) doesNotRecognizeSelector:] + 186
3 CoreFoundation 0x00007fff9167702e ___forwarding___ + 414
4 CoreFoundation 0x00007fff91676e18 _CF_forwarding_prep_0 + 232
5 Tweets 0x0000000100000d1a main + 378
6 libdyld.dylib 0x00007fff908e67e1 start + 0
)
libc++abi.dylib: terminate called throwing an exception
What's wrong? I have followed a tutorial perfectly but I am the only one getting the error.

I ran your code. My results didn't agree with yours. I didn't crash, but I did receive (null) from the final NSLog call.
Yes, you should be checking the result of +[NSJSONSerialization JSONObjectWithData:options:error]. As #HotLicks has pointed out to you quite rightfully, if the result you get is nil, examining the error object can reveal important clues as to what's gone wrong.
But in this case, it's academic because the result (again, in my case) wasn't nil. The real problem, however, is that you don't appear to have an understanding of your data's schema. jsonObject is a dictionary, but it has only two keys, results and resultCount, and that's the reason you're getting nil from [jsonObject objectForKey:#"trackName"]; trackName isn't one of the keys.
Those two keys that you do get, however, should tell you plenty. It told me enough to try this:
NSArray *results = [jsonObject objectForKey:#"results"];
NSDictionary *dictionary = [results objectAtIndex:0];
id latestLoans = [dictionary objectForKey:#"trackName"];
and got a result:
Harry Potter and the Deathly Hallows - Part 1
In other words, I simply got the first dictionary in the array for results, and asked it for the object it had for trackName.
Since you were originally asking for an array, I'm guessing that you wanted all the values for that particular key, so if you use this:
NSArray *latestLoans = [jsonObject valueForKeyPath:#"results.trackName"];
it provides a list of 50 values corresponding to the trackName key in the dictionaries under the results key.
EDIT:
One other thing you really need to do is to protect yourself against the possibility of nil being returned from your call to -[NSData initWithContentsOfURL:] by checking for it before calling anything else. This alone won't fix your inability to get a response, but it will keep you from crashing. And if you do receive nil, be sure to check the domain and code properties of the error object you get back to get an idea of what's going wrong.

Related

Creating generic Objective C relationship model

I'm trying to setup generic model for retrieving data from a backend and processing the data in my iPhone app. I'm trying to accomplish this by creating a base-class for all class in which all logic is defined for retrieving, saving and linking data. This last part is the part I'm struggling on.
In every class I define the object name (in Core Data) and if a certain object has relationships to other objects, also and array of the names of the objects with two arrays (one for hasOne and one for hasMany).
However I can't seem to accomplish cast retrieved objects to a certain class which is stored as a string. This is the code I currently have:
/**
Update the relationsships of an object which has relationsships from the type 'HasOne'.
#param object
Object from which the relations has to be updated.
*/
- (void)updateRelationshipsHasOne:(id)object {
for(NSString *relation in self.hasOne) {
Class class = NSClassFromString(self.table);
id anInstance = [class alloc];
anInstance = object;
NSString *key = [[NSString alloc] initWithFormat:#"%#_id",[relation lowercaseString]];
id delegata = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [delegata managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:relation inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat: #"db_id == %i",[[object valueForKey:key] intValue]];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if(fetchedObjects && [fetchedObjects count] > 0) {
id otherInstance = [fetchedObjects objectAtIndex:0];
SEL s = NSSelectorFromString([[NSString alloc] initWithFormat:#"set%#",relation]);
[anInstance performSelector:s withObject:otherInstance];
}
}
}
If I cast both 'anInstance' and 'otherInstance' to the desired classes, everything goes well. However the whole purpose is to make the method generic, so I need some way to be able to cast both variables to Classes which are stored as strings.
Thanks a lot in advance for any help!
Edit:
The error message I'm receiving is:
2016-03-21 20:34:19.024 DeDamen[12303:834645] -[Heat setEvent]: unrecognized selector sent to instance 0x7fe2829d8cd0
2016-03-21 20:34:19.026 DeDamen[12303:834645] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Heat setEvent]: unrecognized selector sent to instance 0x7fe2829d8cd0'
*** First throw call stack:
(
0 CoreFoundation 0x0000000109e68e65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001094c0deb objc_exception_throw + 48
2 CoreFoundation 0x0000000109e7148d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000109dbe90a ___forwarding___ + 970
4 CoreFoundation 0x0000000109dbe4b8 _CF_forwarding_prep_0 + 120
5 ******* 0x0000000105d255ab -[CommonBase updateRelationshipsHasOne:] + 1627
6 ******* 0x0000000105d24e60 -[CommonBase updateRelationships:] + 256
7 ******* 0x0000000105d248a9 -[CommonBase save:handler:] + 1065
****
)
libc++abi.dylib: terminating with uncaught exception of type NSException
In here the model 'Heat' refers to the object 'anInstance' and the model 'Event' refers to the object 'otherInstance'. The relations ship is: a Heat has one Event and an Event has many Heats'

Segmentation fault - performSelectorOnMainThread on [NSFileManager defaultManager]

This code seems to be causing a segmentation fault from time to time:
[[NSFileManager defaultManager] performSelectorOnMainThread:#selector(removeItemAtPath:error:) withObject:filePath waitUntilDone:YES];
I want to perform all operations on files in the main thread to avoid conflicts like removing a file while the whole folder is iterated.
It produces this error:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x1084
Application Specific Information:
objc_msgSend() selector name: release
This is the stack trace of the crashed main thread:
Thread 0 Crashed:
0 libobjc.A.dylib 0x39fc8636 objc_msgSend + 22
1 Foundation 0x30214c67 __NSThreadPerformPerform + 452
2 CoreFoundation 0x2f7f6fef __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 12
3 CoreFoundation 0x2f7f64b7 __CFRunLoopDoSources0 + 204
4 CoreFoundation 0x2f7f4ca7 __CFRunLoopRun + 628
5 CoreFoundation 0x2f75f769 CFRunLoopRunSpecific + 522
6 CoreFoundation 0x2f75f54b CFRunLoopRunInMode + 104
7 GraphicsServices 0x346bc6d3 GSEventRunModal + 136
8 UIKit 0x320be891 UIApplicationMain + 1134
9 Pocket3 0x00050243 main (main.m:4)
10 libdyld.dylib 0x3a4bcab7 start + 0
What am I doing wrong?
It looks like the NSFileManager is deallocated too early, but how can it be if it is a singleton?
Could it have something to do with the method [NSFileManager defaultManager] which is said to not be thread safe?
Update: new answer
NSFileManager is threadsafe (as long as you are not using its delegate, which you don't, and which you shouldnt do with the -defaultManager anyways). You can just call [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error] on whatever thread you are currently on. There is no advantage on doing it on the main thread only. In fact, performance will probably better if you update the filesystem in a background thread, because the UI will not block if the operation takes longer than expected.
Old answer (why the crash did happen)...
The method -removeItemAtPath:error: wants two objects, but you are providing only one. So the second paramter (NSError **) that the -removeItemAtPath:error: method will see, is just some garbage that lies next to the filePath pointer in memory.
There is no version of -performSelectorOnMainThread:... that takes two objects. You may use dispatch_sync instead:
dispatch_sync(dispatch_get_main_queue(), ^() {
NSError *error = nil;
BOOL ok = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
if(!ok) {
NSLog(#"an error happened: %#", error);
}
}

NSRangeException for empty array except there is an array?

I'm having this problem where I keep getting this error in my console:
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array'
Here is my code for retrieving the data from the XML document:
CXMLDocument *worldweather = [[CXMLDocument
alloc]initWithContentsOfURL:[NSURL URLWithString:[NSString
stringWithFormat:#"http://free.worldweatheronline.com/feed/weather.ashx?q=%#&format=xml&num_of_days=4&key=0ded69e02b171832121504",query]]
options:0 error:nil];
weathercondition = [[[worldweather nodesForXPath:#"/data/current_condition/weatherIconUrl" error:nil]
objectAtIndex:0] stringValue];
The location that Xcode is using is Williams, CA and the query sent is
Williams+CA
When I plug this into my URL, it works and I get my XML file, but why am I getting this message in my console???
This is driving me crazy. All help would be GREATLY appreciated! Thanks in advance!
Seems that you think that [worldweather nodesForXPath:#"/data/current_condition/weatherIconUrl" error:nil] is NSArray with at least one object inside the array. This is clearly not the case, and you get an error saying that there is no object at index 0, which means that array is empty.
If you are not sure there is at least one object inside an NSArray do not just call objectAtIndex:0.
You could first check how many elements are there in array and then do the work like:
NSArray *weatherArray = [worldweather nodesForXPath:#"/data/current_condition/weatherIconUrl" error:nil];
if ([weatherArray count] > 0){
weathercondition = [[weatherArray objectAtIndex:0] stringValue];
}
If you are not sure what you are getting back from the server, see what is in the array:
NSLog(#"%#", weatherArray);
or check how many elements there are:
NSLog(#"elements in Array: %i", [weatherArray count]);
One additional useful thing you can use is for example [weatherArray lastObject], this will always return the last element of the array and will return nil even if the array is empty (it will not crash like objectAtIndex:0)

What's calling CFStringCreateFromExternalRepresentation?

I'm rather confused by this stack trace (only the confusing part is shown):
-[NSXMLDocument length]: unrecognized selector sent to instance 0x10187e010
An uncaught exception was raised
-[NSXMLDocument length]: unrecognized selector sent to instance 0x10187e010
(
0 CoreFoundation 0x00007fff8f5d6286 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff9213bd5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff8f6624ce -[NSObject doesNotRecognizeSelector:] + 190
3 CoreFoundation 0x00007fff8f5c3133 ___forwarding___ + 371
4 CoreFoundation 0x00007fff8f5c2f48 _CF_forwarding_prep_0 + 232
5 CoreFoundation 0x00007fff8f548c66 CFDataGetLength + 118
6 CoreFoundation 0x00007fff8f5791df CFStringCreateFromExternalRepresentation + 31
7 asLJ 0x0000000100013828 +[stripHTML stripAllHtmlFromString:] + 212
In particular, I don't understand where the call to CFStringCreateFromExternalRepresentation is happening, so I don't know what part of my code (+[stripHTML stripAllHtmlFromString:]) is causing the exception. What's causing the call to CFStringCreateFromExternalRepresentation? If it's obvious, what is it that I'm doing wrong that's causing the exception? In the future, how can I go about determining what's calling CFStringCreateFromExternalRepresentation?
Here's +[stripHTML stripAllHtmlFromString:]:
+ (NSString *)stripAllHtmlFromString:(NSString *)inputString
{
// based on code from http://sugarmaplesoftware.com/25/strip-html-tags/#comment-71
NSError *theError = NULL;
NSString *modifiedInputString = [NSString stringWithFormat:#"%#\n\n\n\n\n\n\n\n\n\n\n\n",inputString]; // adding some spare newlines at the end to ensure that things will work even with a short non-HTML string
NSXMLDocument *theDocument = [[NSXMLDocument alloc] initWithXMLString:modifiedInputString
options:NSXMLDocumentTidyHTML
error:&theError];
NSString *theXSLTString = #"<?xml version='1.0' encoding='utf-8'?>"
"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:xhtml='http://www.w3.org/1999/xhtml'>"
"<xsl:output method='text'/>"
"<xsl:template match='xhtml:head'></xsl:template>"
"<xsl:template match='xhtml:script'></xsl:template>"
"</xsl:stylesheet>";
NSData *theData = [theDocument objectByApplyingXSLTString:theXSLTString arguments:NULL error:&theError];
[theDocument release];
return [[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease];
}
Oh, actually, probably -objectByApplyingXSLTString:arguments:error: returned an NSXMLDocument and not an NSData. So, the call to -[NSString initWithData:encoding:] is invoking -length on what it thinks is an NSData, but NSXMLDocument doesn't recognize that.
Ken Thomases's answer seems to have it exactly right—for some reason, for very short input (particularly the empty string), -objectByApplyingXSLTString:arguments:error: with the given XSLT returns an NSXMLDocument (even though I don't think it should). To fix it, I first detect whether we got an NSXMLDocument and if so, turn it into a string representation of the XML and feed that back into the method; otherwise assume we got the NSData that we'd originally expected.
Replacing the last 3 lines of the given method (from NSData *theData =... on) with the code below seems to have fixed the issue.
// Had a report of an exception that seemed to indicate objectByApplyingXSLTString:arguments:error: was returning an NSXMLDocument objectinstead of an NSData object, so let's guard against that. (discussed at https://stackoverflow.com/q/10669479/291280 )
NSObject *XSTLresult = [theDocument objectByApplyingXSLTString:theXSLTString arguments:NULL error:&theError];
[theDocument release];
if ([XSTLresult isKindOfClass:[NSXMLDocument class]]) {
// If the result is an NSXMLDocument, call XMLData to get an NSData object, turn it into a string, and feed that back into this method...
return [self stripAllHtmlFromString:[[[NSString alloc]
initWithData:[(NSXMLDocument *)XSTLresult XMLData]
encoding:NSUTF8StringEncoding]
autorelease]
];
} else {
// Otherwise, assume we have an NSData object.
return [[[NSString alloc] initWithData:(NSData *)XSTLresult encoding:NSUTF8StringEncoding] autorelease];
}

"unrecognized selector sent to class" when calling category method from a library

Problem
This question may seem a bit long, but I try to give as much information as possible, since I am really staggered by this.
I am currently working an a library which should automate XML document parsing. But I am running into a problem now testing the library for the first time.
I have a library class called CSXDocumentLayout which represents the layout of a document. This class contains the private method - (NSError *)readLayoutDocument:(NSString *)fpath called from an init method.
/* MARK: Reading in Layouts */
- (NSError *)readLayoutDocument:(NSString *)fpath {
CSXDocumentLayout *layout;
CSXXMLParser *parser;
BOOL state;
layout = [CSXDocumentLayout layoutDocumentLayout];
parser = [[CSXXMLParser alloc] initWithDocumentLayouts:
[NSArray arrayWithObject:layout]];
parser.file = fpath;
state = [parser parse];
if(state == NO || parser.error != nil) {
return parser.error;
}
return nil;
}
This method will read in an XML document representing the layout of an other XML document. It is parsed by the class CSXXMLParser, which I want to test.
I create an object representing a layout document with +[CSXDocumentLayout layoutDocumentLayout]. This method is implemented in the category CSXDocumentLayout (CSXLayoutObject).
Below is my test file:
#import <Foundation/Foundation.h>
#import <CeasyXML.h>
int main(int argc, const char **argv) {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSString *file;
file = [NSString stringWithUTF8String:__FILE__];
file = [file stringByDeletingLastPathComponent];
file = [file stringByAppendingPathComponent:#"Layout.xml"];
CSXDocumentLayout *layout;
NSError *error;
layout = [[CSXDocumentLayout alloc] initWithLayoutDocument:file
error:&error];
if(layout == nil) {
NSLog(#"Could not create layout: %#", error);
exit(0);
}
NSLog(#"Layout:\n%#", layout);
[pool release];
return 0;
}
This file compiles to a separate executable linked to my static library libceasyxml.a. Everything compiles just fine without any warnings.
But when I run it I get a unrecognized selector sent to class exception:
2012-05-02 16:59:47.620 TestApp[1887:a0f] +[CSXDocumentLayout layoutDocumentLayout]: unrecognized selector sent to class 0x1000064c8
2012-05-02 16:59:47.791 TestApp[1887:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[CSXDocumentLayout layoutDocumentLayout]: unrecognized selector sent to class 0x1000064c8'
*** Call stack at first throw:
(
0 CoreFoundation 0x00007fff83e47784 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x00007fff84604f03 objc_exception_throw + 45
2 CoreFoundation 0x00007fff83ea11a0 __CFFullMethodName + 0
3 CoreFoundation 0x00007fff83e198ef ___forwarding___ + 751
4 CoreFoundation 0x00007fff83e15a38 _CF_forwarding_prep_0 + 232
5 TestApp 0x0000000100001512 -[CSXDocumentLayout(Private) readLayoutDocument:] + 49
6 TestApp 0x00000001000010d4 -[CSXDocumentLayout initWithLayoutDocument:error:] + 96
7 TestApp 0x0000000100001017 main + 179
8 TestApp 0x0000000100000f5c start + 52
9 ??? 0x0000000000000001 0x0 + 1
)
I find it very disturbing that I cannot call the class method +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout], though I can call both -[CSXDocumentLayout initWithLayoutDocument:error:], and -[CSXDocumentLayout(Private) readLayoutDocument:].
Research
I checked if the method is defined in the output files by running nm file and it is, well partly:
In libceasyxml.a, it is defined (nm libceasyxml.a)
...
libceasyxml.a(CSXDocumentLayout+CSXLayoutObject.o):
0000000000000100 t +[CSXDocumentLayout(CSXLayoutObject) classAttributeLayout]
00000000000020e0 s +[CSXDocumentLayout(CSXLayoutObject) classAttributeLayout].eh
000000000000056b t +[CSXDocumentLayout(CSXLayoutObject) documentElementLayout]
0000000000002180 s +[CSXDocumentLayout(CSXLayoutObject) documentElementLayout].eh
0000000000000402 t +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout]
0000000000002148 s +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout].eh
0000000000000200 t +[CSXDocumentLayout(CSXLayoutObject) layoutElementLayout]
0000000000002110 s +[CSXDocumentLayout(CSXLayoutObject) layoutElementLayout].eh
0000000000000000 t +[CSXDocumentLayout(CSXLayoutObject) nameAttributeLayout]
00000000000020b0 s +[CSXDocumentLayout(CSXLayoutObject) nameAttributeLayout].eh
0000000000002098 s EH_frame1
0000000000001c49 s LC0
...
In TestApp, it is NOT defined (nm TestApp), actually I can't find any method with the category name CSXLayoutObject.
...
0000000100001271 t -[CSXDocumentLayout setDocumentClassString:]
00000001000013a8 t -[CSXDocumentLayout setElements:]
0000000100001490 t -[CSXDocumentLayout setName:]
00000001000014db t -[CSXDocumentLayout(Private) readLayoutDocument:]
0000000100004060 t -[CSXElementList dealloc]
00000001000040b0 t -[CSXElementList elements]
...
EDIT: Fixed broken link
I suspect you have run into a known problem of categories embedded in static libraries.
If I am right, try to compile with the linker flags -ObjC (and if that is not enough, also -all_load) and your problem should disappear.
Even though the answer is already selected, I wish the solution to my issue was here, as simple as it may be. Be sure to check that your class is properly checked in the Target Membership field under the File Inspector pane. If you fail to do so then it's only natural to receive the unrecognized selector sent to class error.