Reputation: 291
I'm just starting out on my first 'real' cocoa app. Note that this is Mac, not iPhone.
This function is called when my async download of onemanga finishes, and is intended to parse an NSArray list of manga from it. I get a NSArray from nodesForXPath, and retain it to make sure it's mine. (Also tried retaining it twice, heh). Unfortunately, trying to retrieve the count of the NSArray causes an EXC_BAD_ACCESS. The point of crashing is marked by two comments below.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"Download Succeeded! Received %d bytes of data. Beginning Parse.",[mangaListData length]);
NSString* theQuery = [[NSString alloc]initWithString:@"//tr/td[@class=\"ch-subject\"]/text()"];
NSError *XMLError=nil;
NSError *XPathError=nil;
NSString* mangaListHTML;
NSString* fixedMangaListHTML;
mangaListHTML = [[NSString alloc] initWithData:mangaListData encoding:NSUTF8StringEncoding];
fixedMangaListHTML = [mangaListHTML stringByReplacingOccurrencesOfString:@" & " withString:@" & "];
NSXMLDocument* xmlDoc = [[NSXMLDocument alloc] initWithXMLString:fixedMangaListHTML
options:(NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA)
error:&XMLError];
if (XMLError) {
NSLog(@"XML Parse error: %@", XMLError);
return;
};
[fixedMangaListHTML release];
[mangaListHTML release];
NSArray* results = [[xmlDoc nodesForXPath:theQuery error:&XPathError] retain];
if (XMLError) {
NSLog(@"Parse error: %@", XPathError);
return;
};
NSLog(@"Parsing complete. Manga List = ");
//CRASH HAPPENS HERE
NSLog(@"Size of array: %@", [results count]);
//CRASH HAPPENS ABOVE
for(NSXMLNode* title in results){
NSLog(@"%@\n", title.description);
};
[XMLError release];
[XPathError release];
[connection release];
[mangaListData release];
}
Heres the output of where
in gdb. (I don't really know how to use gdb yet, so any commands I could run to get more info here would be highly appreciated.)
#0 0x00007fff855691d1 in objc_msgSend_vtable5 ()
#1 0x00007fff87e97207 in _NSDescriptionWithLocaleFunc ()
#2 0x00007fff8509ba2d in _CFStringAppendFormatAndArgumentsAux ()
#3 0x00007fff8509aead in _CFStringCreateWithFormatAndArgumentsAux ()
#4 0x00007fff85119f5f in _CFLogvEx ()
#5 0x00007fff87ef937f in NSLogv ()
#6 0x00007fff87ef9317 in NSLog ()
#7 0x0000000100002bca in -[TMMoneManga connectionDidFinishLoading:] (self=0x1001999f0, _cmd=0x7fff8803b5de, connection=0x1001689a0) at /Users/ripdog/Documents/TheMangaMachine/TMMoneManga.m:120
#8 0x00007fff87f16b8c in _NSURLConnectionDidFinishLoading ()
#9 0x00007fff8063f18e in URLConnectionClient::_clientDidFinishLoading ()
#10 0x00007fff806a4502 in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload ()
#11 0x00007fff8062b8fb in URLConnectionClient::processEvents ()
#12 0x00007fff8062b6d8 in MultiplexerSource::perform ()
#13 0x00007fff850b6f21 in __CFRunLoopDoSources0 ()
#14 0x00007fff850b5119 in __CFRunLoopRun ()
#15 0x00007fff850b48df in CFRunLoopRunSpecific ()
#16 0x00007fff80b83ada in RunCurrentEventLoopInMode ()
#17 0x00007fff80b838df in ReceiveNextEventCommon ()
#18 0x00007fff80b83798 in BlockUntilNextEventMatchingListInMode ()
#19 0x00007fff8845fa2a in _DPSNextEvent ()
#20 0x00007fff8845f379 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#21 0x00007fff8842505b in -[NSApplication run] ()
#22 0x00007fff8841dd7c in NSApplicationMain ()
#23 0x00000001000017cd in main (argc=1, argv=0x7fff5fbff6c0) at /Users/ripdog/Documents/TheMangaMachine/main.m:13
Thanks a lot in advance.
Upvotes: 1
Views: 481
Reputation: 6545
The problem is with your format string. The %@
specifier will display an Objective-C object, but [result count]
is an integer. The correct format specifier for an integer is %d
.
For reference, here is a complete list of Objective-C string format specifiers.
Your question indicated that the crash happens when you try to retrieve [result count]
. However if you look at the call stack, your code is frame #7, and the next function on the stack (frame #6) is NSLog. So this tells you the problem is probably something to do with the call to NSLog, and not [result count]
. [result count]
will already have returned before control flow enters NSLog.
There are various techniques for debugging with gdb. Since you are debugging a crash, your focus will mostly be on examining the call stack, variables and memory (as opposed to stepping through your code as it executes.) So for this kind of debugging, these commands are essential:
up
This moves the "focus" of the debugger up one frame of the call stack. Let's say you want to examine the variables in your program. You can't see them in objc_msgSend_vtable5
which is where the debugger is stopped. So use up 7
to jump up seven frames so you're looking at your code.down
Is the opposite of up. Oftentimes you want to look at what led to disaster, so jumping up to your code and then going down, down, down is a way to get an understanding of how disaster unfolded. (This isn't moving you forward and backward in time, of course.)where
Shows you part of the call stack. You already discovered this. My only tip is that you often only care about what's on the top of the call stack. You can use where n
to print the first n frames of the call stack.list
Shows you the source code of the "focussed" frame, with an arrow indicating the execution point. So, for example, up 7
followed by list
should show you the source of connectionDidFinishLoading
with an indicator next to the call to NSLog. Using list
is often more convenient than finding the code in XCode, if you just need to see a few lines of the surrounding context.print
Evaluates an expression and prints it. For example, you could do print [results count]
to see what [results count]
evaluates to. When the debugger is stopped with your program is in a bad state, print
can act funny (it can really run code.) So often simple expressions work better.info
Info can tell you lots of things, but info locals
is really valuable. It shows you the local variables that are in scope in the "focussed" frame of the debugger.Upvotes: 3
Reputation: 9543
count
returns an integer, not an object. Print it with %d
not %@
.
(If you do the latter, you implicitly convert the integer to a pointer to a non-existent object in the wilds of who knows where, and then invoke its description
method.)
Upvotes: 1