NSFetchedResultsController and NSManagedObjectIDResultType crashes - objective-c

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];

Related

How can accessing super in an instance method cause EXC_BAD_ACCESS?

Inside an instance method I'm calling the same selector on the superclass and getting EXC_BAD_ACCESS. I'm using manual reference counting (not ARC), and this is happening in the main thread. Static analysis reports no issues, not that I take that to mean a clean bill of health. The relevant code is as follows:
CommentListMedia.m (stack frame 1 in the trace below):
- (void)play {
if ((comments.isLoading) && (! comments.isLoaded))
playWhenLoaded = YES;
else [super play]; // <-- EXC_BAD_ACCESS happens here
}
MediaControls.m (stack frame 2 in the trace below):
- (void)play {
[media play]; // <-- this calls the code above
[self notifyWithName:MediaControlsDidPlayNotification];
}
MyApp.m (stack frame 11 in the trace below):
- (void)sendEvent:(UIEvent *)event {
[super sendEvent:event]; // <-- this calls the code above
...
}
The superclass of CommentListMedia is SequentialMedia, which doesn't figure into the stack trace because the exception occurs before it's reached.
Unfortunately I'm only seeing this in crash reports (from Crashlytics), and haven't been able to reproduce it myself. What strikes me as odd about it is that the reference to the class instance must have been good to perform the play selector in the first place, but somehow by the time it gets to the end, the reference to the superclass is bad. At first I thought the instance might be auto-released or something, but I'm under the impression that autoreleasing happens on the main thread at the end of the run loop, not at some random time in the middle of a call. Any input on what might be causing this or how to debug it would be appreciated.
The call stack on the main thread looks like this:
0 libobjc.A.dylib objc_msgSend + 5
1 MyApp -[CommentListMedia play]
2 MyApp -[MediaControls play]
3 UIKit -[UIApplication sendAction:to:from:forEvent:] + 90
4 UIKit -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 30
5 UIKit -[UIControl sendAction:to:forEvent:] + 44
6 UIKit -[UIControl _sendActionsForEvents:withEvent:] + 374
7 UIKit -[UIControl touchesEnded:withEvent:] + 590
8 UIKit -[UIWindow _sendTouchesForEvent:] + 528
9 UIKit -[UIWindow sendEvent:] + 832
10 UIKit -[UIApplication sendEvent:] + 196
11 MyApp -[MyApp sendEvent:]
12 UIKit _UIApplicationHandleEventQueue + 7096
13 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14
14 CoreFoundation __CFRunLoopDoSources0 + 206
15 CoreFoundation __CFRunLoopRun + 622
16 CoreFoundation CFRunLoopRunSpecific + 522
17 CoreFoundation CFRunLoopRunInMode + 106
18 GraphicsServices GSEventRunModal + 138
19 UIKit UIApplicationMain + 1136
20 MyApp main
0 libobjc.A.dylib objc_msgSend + 5
1 MyApp -[CommentListMedia play]
That may be a crash in -[SequentialMedia play]. Specifically, if that method returns void and makes a call as the last expression in the method, it may be that the [optimizing] compiler generated a tail call. This would effectively cause the method call to disappear from the stack.
Post the contents of the registers from your crash report. $r0 can be quite illuminating (as it is the first arg and should be a viable object).
Also, if there is heavy concurrency in play in your program, then it could be that the object is being released and deallocated by a secondary thread. But, typically, you would see more than one flavor of odd crash (though sometimes not, if your code makes heavy use of synchronization primitives -- it can be remarkable how consistent a concurrent program behaves from run to run).

NSRunLoop runMode does not always process dispatch_async

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.

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

NSWorkspaceDidTerminateApplicationNotification crashes

So some of my users are getting crashes, and I think iv'e tracked it down to the NSWorkspaceDidTerminateApplicationNotification, I can't reproduce the crash at all so I'm not sure where to go?
here is the generated crash log, maybe I'm missing something obvious:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: invalidate
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff816f211c objc_msgSend + 40
1 com.apple.Foundation 0x00007fff87ef58ea _nsnote_callback + 167
2 com.apple.CoreFoundation 0x00007fff869b3000 __CFXNotificationPost + 1008
3 com.apple.CoreFoundation 0x00007fff8699f578 _CFXNotificationPostNotification + 200
4 com.apple.Foundation 0x00007fff87eec84e -[NSNotificationCenter postNotificationName:object:userInfo:] + 101
5 com.apple.AppKit 0x00007fff878efb58 applicationStatusSubsystemCallback + 593
6 com.apple.LaunchServices 0x00007fff83523e6c LSScheduleNotificationReceiveMessageCallbackFunc(__CFMachPort*, void*, long, void*) + 184
7 com.apple.CoreFoundation 0x00007fff869cf68e __CFMachPortPerform + 366
8 com.apple.CoreFoundation 0x00007fff869a76e1 __CFRunLoopRun + 5201
9 com.apple.CoreFoundation 0x00007fff869a5dbf CFRunLoopRunSpecific + 575
10 com.apple.HIToolbox 0x00007fff80ef07ee RunCurrentEventLoopInMode + 333
11 com.apple.HIToolbox 0x00007fff80ef05f3 ReceiveNextEventCommon + 310
12 com.apple.HIToolbox 0x00007fff80ef04ac BlockUntilNextEventMatchingListInMode + 59
13 com.apple.AppKit 0x00007fff87232e64 _DPSNextEvent + 718
14 com.apple.AppKit 0x00007fff872327a9 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 155
15 com.apple.AppKit 0x00007fff871f848b -[NSApplication run] + 395
16 com.apple.AppKit 0x00007fff871f11a8 NSApplicationMain + 364
and here is the relevant code:
NSNotificationCenter *center = [[NSWorkspace sharedWorkspace] notificationCenter];
[center addObserver:self selector:#selector(appTerminated:) name:NSWorkspaceDidTerminateApplicationNotification object:nil];
- (void)appTerminated:(NSNotification *)note
{
NSString *app = [NSString stringWithFormat:#"%#", [[note userInfo] objectForKey:#"NSApplicationName"]];
if ([app isEqualToString:Somestring])
{
//do something here
}
}
}
If anyone could give me some pointers as to where to look, i'd be eternally grateful, I've been tearing my hair out for days now...
It looks like your window controller is getting deallocated while still being registered with the notification centre. You need to make sure the window controller is unregistered before deallocation. Otherwise, the notification centre will try to post a notification to a deallocated object, which can trigger an EXC_BAD_ACCESS exception.
For instance, in your window controller implementation:
- (void)dealloc {
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
[super dealloc];
}
This will unregister the window controller with regard to every notification it’s registered with the notification centre.
Looks like a notification fired and tried to call an invalidate method on an object that has been deallocated. Turn on NSZombies and try again.