NSRunLoop runMode does not always process dispatch_async - objective-c

I'm trying to get a better understanding of queues and how they work. This snippet is to test their behaviour:
- (void)dispatchQueueTest
{
NSLog( #"Begin test on %# thread", [NSThread isMainThread] ? #"main" : #"other" );
dispatch_semaphore_t s = dispatch_semaphore_create(0);
dispatch_async( dispatch_get_main_queue(), ^{
NSLog( #"Signalling semaphore" );
dispatch_semaphore_signal(s);
});
NSLog( #"Waiting for worker" );
while( dispatch_semaphore_wait( s, DISPATCH_TIME_NOW ) ) {
NSDate* timeout = [NSDate dateWithTimeIntervalSinceNow:10.f];
// Process events on the run loop
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout];
}
dispatch_release(s);
NSLog( #"All sync'd up" );
}
As would be expected it produces this in the log:
Begin test on main thread
Waiting for worker
Signalling semaphore
All sync'd up
What is strange is that if this code is called from, say, - (void)viewDidAppear:(BOOL)animated of a UIViewController, then it changes behaviour. Specifically it deadlocks with the following log:
Begin test on main thread
Waiting for worker
My question is why does NSRunLoop runMode not process the block sent via dispatch_async in this situation but it does in others?

I have a project where I push a PlayerNameEntryViewController onto a navigation controller. I put a breakpoint in -[PlayerNameEntryViewController viewDidAppear:]. Here's the stack trace when the breakpoint was hit:
#0 0x0002d3d3 in -[PlayerNameEntryViewController viewDidAppear:] at /Volumes/b/Users/mayoff/t/hotseat2/hotseat2/Home/PlayerNameEntryViewController.m:39
#1 0x00638fbf in -[UIViewController _setViewAppearState:isAnimating:] ()
#2 0x006392d4 in -[UIViewController __viewDidAppear:] ()
#3 0x006395d7 in -[UIViewController _endAppearanceTransition:] ()
#4 0x00648666 in -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] ()
#5 0x007ee90e in -[UINavigationTransitionView _notifyDelegateTransitionDidStopWithContext:] ()
#6 0x007eec17 in -[UINavigationTransitionView _cleanupTransition] ()
#7 0x007eec86 in -[UINavigationTransitionView _navigationTransitionDidStop] ()
#8 0x005a2499 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#9 0x005a2584 in -[UIViewAnimationState animationDidStop:finished:] ()
#10 0x00497e00 in CA::Layer::run_animation_callbacks(void*) ()
#11 0x02e86515 in _dispatch_main_queue_callback_4CF ()
#12 0x015fe833 in __CFRunLoopRun ()
#13 0x015fddb4 in CFRunLoopRunSpecific ()
#14 0x015fdccb in CFRunLoopRunInMode ()
#15 0x01acd879 in GSEventRunModal ()
#16 0x01acd93e in GSEventRun ()
#17 0x00571a9b in UIApplicationMain ()
#18 0x00002461 in main at /Volumes/b/Users/mayoff/t/hotseat2/hotseat2/main.m:17
Notice frame #11. It's a call to _dispatch_main_queue_callback_4CF. That is the function that runs blocks put on the main queue. So viewDidAppear: was actually called from inside a block that was added to the main queue with dispatch_async.
The main queue is a serial queue. The definition of a serial queue is a queue that only executes one block at a time. If the queue is executing a block, no other block on that queue can start. So when you run the main run loop recursively, the run loop sees that it's already inside a block running on the main queue and doesn't try to start more blocks. That's why your semaphore-signaling block never runs and your app hangs.
Note that sometimes viewDidAppear: is called from inside a queued block, and sometimes it's not. You shouldn't rely on either behavior.

Related

Why would a program pause and not crash when no breakpoints are set?

I have a project that simply pauses, and does not crash. It pauses at the last line in this set:
NSLog(#"%#", nibOptions);
NSLog(#"%#", self.nibName);
NSLog(#"%#", self.nibBundle);
[self.nibBundle loadNibNamed:self.nibName owner:self options:nibOptions];
The NSLogs that precede the pause look totally reasonable. I think everything is connected up correctly. But obviously something is wrong. Any advice on troubleshooting a pause that gives no info? There are no break points set. Thanks. (Xcode 4.2)
EDIT: I'd add that the app comes to the front, then moves behind the Xcode window. The nib/view does not load.
EDIT: Here's the crash log (after the pause is continued):
#0 0x90160332 in __kill ()
#1 0x9015f932 in kill$UNIX2003 ()
#2 0x013e136b in CFHash ()
#3 0x01493c04 in __CFDictionaryStandardHashKey ()
#4 0x013e9114 in CFBasicHashFindBucket ()
#5 0x013e8ad5 in CFDictionaryGetValue ()
#6 0x00588ba4 in +[UIProxyObject mappedObjectForCoder:withIdentifier:] ()
#7 0x00588c9d in -[UIProxyObject initWithCoder:] ()
#8 0x00687fa2 in UINibDecoderDecodeObjectForValue ()
#9 0x006876b7 in -[UINibDecoder decodeObjectForKey:] ()
#10 0x00588ead in -[UIRuntimeConnection initWithCoder:] ()
#11 0x00589629 in -[UIRuntimeEventConnection initWithCoder:] ()
#12 0x00687fa2 in UINibDecoderDecodeObjectForValue ()
#13 0x006879af in UINibDecoderDecodeObjectForValue ()
#14 0x006876b7 in -[UINibDecoder decodeObjectForKey:] ()
#15 0x00588305 in -[UINib instantiateWithOwner:options:] ()
#16 0x0058a010 in -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] ()
#17 0x00002fc5 in -[P3ViewController loadView] at /Users/bryanhanson/Desktop/NastyMarty/P3/Classes/P3ViewController.m:158
#18 0x004305cb in -[UIViewController view] ()
#19 0x00390a73 in -[UIWindow addRootViewControllerViewIfPossible] ()
#20 0x00390ce2 in -[UIWindow _setHidden:forced:] ()
#21 0x00390ea8 in -[UIWindow _orderFrontWithoutMakingKey] ()
#22 0x00397d9a in -[UIWindow makeKeyAndVisible] ()
#23 0x0000297e in -[P3AppDelegate application:didFinishLaunchingWithOptions:] ()
#24 0x003689d6 in -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] ()
#25 0x003698a6 in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] ()
#26 0x00378743 in -[UIApplication handleEvent:withNewEvent:] ()
#27 0x003791f8 in -[UIApplication sendEvent:] ()
#28 0x0036caa9 in _UIApplicationHandleEvent ()
#29 0x01bc7fa9 in PurpleEventCallback ()
#30 0x014a51c5 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#31 0x0140a022 in __CFRunLoopDoSource1 ()
#32 0x0140890a in __CFRunLoopRun ()
#33 0x01407db4 in CFRunLoopRunSpecific ()
#34 0x01407ccb in CFRunLoopRunInMode ()
#35 0x003692a7 in -[UIApplication _run] ()
#36 0x0036aa9b in UIApplicationMain ()
#37 0x00002458 in main ()
The window moves behind Xcode because it gains focus when your app pauses/crashes. And the view doesn't load because the you just called loadnib or did not yet (depending on the line where the app pauses).
Now, as you say that your app dies if you resume running it, then it is a crash and not a pause.
Try to verify that the nib name and options are correct, and that the xib file is actually there and bundled with the app.
Edit
Try the solution in the accepted answer here.
It's crashing in NibDecoder, i.e. when loading your XIB files. You probably have a reference in there to an object or property that doesn't exist or isn't initialized.
And the conclusion of the OP:
I built everything up again from scratch in my custom controller object and i've bypassed what was killing me last time. Every single change I made I compiled and ran in the iPhone sim to make sure I didn't trip myself up. I think my connections to my Controller object must have been incorrect and I was doing something else. So lesson learned is compile and test a lot when doing IB layouts... not just when using Xcode!
So just try doing like him: verifying the connections in the xib file, or if possible, start it again and add thing step by step to see what is causing the crash.
It's not a pause, it's a crash that looks like a pause when you NSLog something of the wrong type. One of those NSLogs is not an object and cannot be displayed with "%#".
Hit pause, and take a look at your threads. I bet you have a circular inclusion somewhere. It will look something like this:
1 -[MyClass2 init]
2 -[MyClass1 init]
3 -[MyClass3 init]
4 -[MyClass2 init]
5 -[MyClass1 init]
6 -[MyClass3 init]
7 -[MyClass2 init]
8 -[MyClass1 init]
9 -[ApplicationDelegate appFinishedLaunching]
10 UIApplicationMain
It will crash eventually. But until it does, it just looks like it's waiting for something. Check for something where MyClass1 #imports MyClass2 which #imports MyClass3 which #imports MyClass1 all over again.
Is this on Snow Leopard? There's a bug where if the runtime crashes you and sends you a message explaining why, you don't get the message in the Console. For example, there could be something wrong with your nib so the nib-loading fails. But you're never getting the Console message explaining why.
EDIT: The best solution is to install Lion and run it on Lion; the bug doesn't happen there. Another possibility (this is what I do) is set a global exception on [NSException raise] and set breakpoints on. When the crash occurs, you will pause at that global breakpoint and you then type po $eax in the Console and you'll get the message from the runtime - if you're lucky.

KVO/KVC crash on reloading previously unloaded bundles

I'm running into an issue with loadable bundles and KVO. It seems that any class that has KVO observers attached to an instance of it cannot be safely be unloaded via NSBundle's -unload method.
I'm doing the following:
for (int i = 0; i < 100; i++)
{
[bundle load];
Class bundleClass = [bundle principalClass];
[[[bundleClass alloc] init] release];
[bundle unload];
}
And in the bundle's principle class -init method,
[self addObserver: self
forKeyPath: #"name"
options: 0
context: nil];
self.name = #"jim";
The loop gets through a number of iterations, sometimes crashing on the second time round, sometimes on the thirtieth.
It always crashes with this backtrace, with the EXC_BAD_ACCESS signal.
#0 0x00007fff8a30deab in objc_msgSend ()
#1 0x00007fff8609d862 in NSKeyValueNotifyObserver ()
#2 0x00007fff860be99b in NSKeyValueDidChange ()
#3 0x00007fff8606b0fb in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] ()
#4 0x00000001007a4c2c in -[Bundle init] (self=0x101902130, _cmd=0x7fff8ea369b0) at /Users/joerick/Desktop/bundleTest/testbundle/Bundle.m:26
#5 0x0000000100001731 in -[SIAppDelegate applicationDidFinishLaunching:] (self=0x100326a90, _cmd=0x7fff876e285f, aNotification=0x100131ea0) at /Users/joerick/Desktop/bundleTest/bundleTest/SIAppDelegate.m:28
#6 0x00007fff8606ade2 in __-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_1 ()
#7 0x00007fff8b470e0a in _CFXNotificationPost ()
#8 0x00007fff86057097 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#9 0x00007fff8e1bbaa7 in -[NSApplication _postDidFinishNotification] ()
#10 0x00007fff8e1bb80d in -[NSApplication _sendFinishLaunchingNotification] ()
....
Full code here
You can download a sample project showing this issue here.
I'm thinking that this is a bug in Cocoa, but I wonder if anybody could see if I'm doing anything stupid here?
I've reported this to Apple.
rdar://11017946

View interpretKeyEvents: but pass unwanted ones up the responder chain?

I'd really like my custom view to work with -moveLeft:, -deleteForward:, -selectAll:, etc., but I'd also like to pass any keys I didn't care about onward up the responder chain. Right now I'm overriding -keyDown: to call [self interpretKeyEvents:[NSArray arrayWithObject:event]];, but this seems to hog all the key events, even ones my view doesn't respond to.
Is there any way to pass unwanted events up the chain, but still respond to -moveLeft:, etc.? Or do I need to implement all my own actions in -keyDown: so that I know what I did and did not respond to?
Came across this trying to find a solution to this same problem. Never found anything online, but I came up with something that seems to work well so far. Here's what I'm doing:
Subclass your NSTextView (or whatever you're using) and create an instance variable to temporarily store the key down event . . .
#interface MyTextView : NSTextView {
NSEvent* _keyDownEvent;
}
#end
Then define your view's methods like so (take out the retain/release junk if you're using automatic reference counting):
#implementation MyTextView
- (id)initWithFrame:(NSRect)frame {
if (self = [super initWithFrame:frame]) {
_keyDownEvent = nil;
}
return self;
}
- (void)keyDown:(NSEvent*)event {
[_keyDownEvent release];
_keyDownEvent = [event retain];
[super keyDown:event];
}
- (void)doCommandBySelector:(SEL)selector {
if (_keyDownEvent && selector == #selector(noop:)) {
if ([self nextResponder]) {
[[self nextResponder] keyDown:[_keyDownEvent autorelease]];
} else {
[_keyDownEvent release];
}
_keyDownEvent = nil;
} else {
[super doCommandBySelector:selector];
}
}
- (void)dealloc {
[_keyDownEvent release];
[super dealloc];
}
#end
Here's how I arrived at this. When a key press isn't handled, you hear a beeping tone. So, I set a breakpoint on NSBeep(), and when the program broke, I spit out a stack trace in GDB:
#0 0x00007fff96eb1c2d in NSBeep ()
#1 0x00007fff96e6d739 in -[NSResponder doCommandBySelector:] ()
#2 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#3 0x00007fff96fda826 in -[NSWindow doCommandBySelector:] ()
#4 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#5 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#6 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#7 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#8 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#9 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#10 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#11 0x00007fff96f486ce in -[NSTextView doCommandBySelector:] ()
#12 0x00007fff96da1c93 in -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] ()
#13 0x00007fff970f5382 in -[NSTextInputContext handleEvent:] ()
#14 0x00007fff96fbfd2a in -[NSView interpretKeyEvents:] ()
#15 0x00007fff96f38a25 in -[NSTextView keyDown:] ()
#16 0x0000000100012889 in -[MyTextView keyDown:] (self=0x1004763a0, _cmd=0x7fff972b0234, event=0x100197320) at /path/MyTextView.m:24
#17 0x00007fff96a16b44 in -[NSWindow sendEvent:] ()
#18 0x00007fff969af16d in -[NSApplication sendEvent:] ()
#19 0x00007fff969451f2 in -[NSApplication run] ()
#20 0x00007fff96bc3b88 in NSApplicationMain ()
#21 0x00000001000015e2 in main (argc=3, argv=0x7fff5fbff8f0) at /path/main.m:12
What's happening is this: When the key down event isn't used for text input, a "noop" command is sent up the response chain. By default this triggers a beep when it falls off the response chain. In my solution, the NSTextView subclass catches the noop command and instead throws the original keyDown event down the response chain. Then your NSWindow or other views will get any unused keyDown events as normal.
This is my swift implementation of #daxnitro's answer, and seems to work:
import Cocoa
class EditorTextView: NSTextView {
private var keyDownEvent: NSEvent?
required init?(coder aCoder: NSCoder) {
super.init(coder: aCoder)
}
override init() {
super.init()
}
override init(frame frameRect: NSRect, textContainer aTextContainer: NSTextContainer!) {
super.init(frame: frameRect, textContainer: aTextContainer)
}
override func keyDown(event: NSEvent) {
keyDownEvent = event
super.keyDown(event)
}
override func doCommandBySelector(aSelector: Selector) {
if aSelector != NSSelectorFromString("noop:") {
super.doCommandBySelector(aSelector)
} else if keyDownEvent != nil {
self.nextResponder?.keyDown(keyDownEvent!)
}
keyDownEvent = nil
}
}
I had a closely related issue with a custom NSTextView in an NSTableView. I wanted to be able to shift-select text in the NSTextView, but when all the text was selected, pass the shift-select up the responder chain to the NSTableView.
My solution was simply to override responds(to:) on my NSTextView and decide whether I wanted to handle it there.
override func responds(to aSelector: Selector!) -> Bool {
if aSelector == #selector(moveUpAndModifySelection(_:)) {
return selectedRange().location != 0
}
return super.responds(to: aSelector)
}

NSFetchedResultsController and NSManagedObjectIDResultType crashes

I´m currently working on an ipad app in which I fetch a lot of data with core data. To keep memory profile low I´m setting the requests resultType to NSManagedObjectIDResultType and grabbing objects with the -objectWithID: Method whenever I need real data.
Everything works as expected. The problem is when it comes to adding/removing Objects from my table view (from the context).
Thats a piece of code I call in my tableView:commitEditingStyle:forRowAtIndexPath:
if(editingStyle == UITableViewCellEditingStyleDelete)
{
NSManagedObjectID *ID = [fetchedResultsController objectAtIndexPath: indexPath];
NSManagedObject *objectToDelete = [self.managedObjectContext objectWithID: ID];
[self.managedObjectContext deleteObject: objectToDelete];
[self.managedObjectContext save: nil];
}
It throws me an exception: "* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[_NSObjectID_48_0 objectID]: unrecognized selector sent to instance 0x5e56900'"
Trace:
#0 0x9953cef6 in __kill
#1 0x9953cee8 in kill$UNIX2003
#2 0x995cf62d in raise
#3 0x995e56e4 in abort
#4 0x95826fda in __gnu_cxx::__verbose_terminate_handler
#5 0x02d9d61c in _objc_terminate
#6 0x9582517a in __cxxabiv1::__terminate
#7 0x958251ba in std::terminate
#8 0x958252b8 in __cxa_throw
#9 0x02d9d3d8 in objc_exception_throw
#10 0x02c84a5b in -[NSObject doesNotRecognizeSelector:]
#11 0x02c01676 in ___forwarding___
#12 0x02c009f2 in __forwarding_prep_0___
#13 0x0281f0f7 in -[_PFBatchFaultingArray arrayFromObjectIDs]
#14 0x0281fe4b in -[_PFMutableProxyArray managedObjectIDAtIndex:]
#15 0x0281ec8e in -[_PFMutableProxyArray indexOfManagedObjectForObjectID:]
#16 0x028823b8 in -[NSFetchedResultsController(PrivateMethods) _preprocessDeletedObjects:deletesInfo:sectionsWithDeletes:]
#17 0x02885159 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidChange:]
#18 0x00065586 in _nsnote_callback
#19 0x02beb165 in _CFXNotificationPostNotification
#20 0x0005c2ca in -[NSNotificationCenter postNotificationName:object:userInfo:]
#21 0x027d838d in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postObjectsDidChangeNotificationWithUserInfo:]
#22 0x0283fe83 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _createAndPostChangeNotification:withDeletions:withUpdates:withRefreshes:]
#23 0x027b9af6 in -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:]
#24 0x027f4a61 in -[NSManagedObjectContext save:]
#25 0x0035d361 in -[UITableView(UITableViewInternal) animateDeletionOfRowWithCell:]
#26 0x00306cee in -[UIApplication sendAction:to:from:forEvent:]
#27 0x0038043e in -[UIControl sendAction:to:forEvent:]
#28 0x003828c0 in -[UIControl(Internal) _sendActionsForEvents:withEvent:]
#29 0x0038146d in -[UIControl touchesEnded:withEvent:]
#30 0x00325de8 in -[UIWindow _sendTouchesForEvent:]
#31 0x0030b643 in -[UIApplication sendEvent:]
#32 0x003131d8 in _UIApplicationHandleEvent
#33 0x0351617c in PurpleEventCallback
#34 0x02bd289c in CFRunLoopRunSpecific
#35 0x02bd18a8 in CFRunLoopRunInMode
#36 0x0351489d in GSEventRunModal
#37 0x03514962 in GSEventRun
#38 0x00311372 in UIApplicationMain
#39 0x00002436 in main at main.m:14
I assume this is an issue with the NSFetchedResultsController and NSManagedObjectIDs. When I set its delegate to nil its not crashing (even crashes with empty delegate methods).
Any idea? Would it be a good idea if I get rid of the NSFetchedResultsController and doing updates manually by observing NSManagedObjectContext notifications?
I think [fetchedResultsController objectAtIndexPath: indexPath]; is returning something that is not a NSManagedObjectID instance, but an Instance of NSObject.
From apple's documentation, the method:
objectAtIndexPath:
Returns the object at the given index
path in the fetch results.
not the ID of the object, try commenting out or deleting the line:
NSManagedObject *objectToDelete = [self.managedObjectContext objectWithID: ID];
and replacing
[self.managedObjectContext deleteObject: objectToDelete];
with
[self.managedObjectContext deleteObject: ID];

EXC_BAD_ACCESS in an NSArray created 3 lines before crash

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.
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.
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.)