views:

56

answers:

2

I get the following error:

'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'condition' between objects in different contexts

when running my iphone app. The relevant part of my model looks like this:

AssessmentTree
-has one TreeCrown

TreeCrown
-has one TreeCrownCondition
-has one AssessmentTree

TreeCrownCondition
-has many TreeCrowns

For the sake of context, I'll mention that this part of the model is designed to allow an arborist to record the condition of a tree's crown. It stores a list of options for assessing the tree crown that can also be edited by the user (So TreeCrownConditions contains the options, and TreeCrown.condition points to the specific selection made in an assessment).

I have a UIPickerView that loads these options and associates the selected option with the AssessmentTree, using the following code in didSelectRow:inComponent:

TreeCrownCondition *fc = (TreeCrownCondition *)[conditionArray objectAtIndex:[conditionPicker selectedRowInComponent:0]];
tree.crown.condition = fc;

When I run this, the first few times I select an option everything is fine, but sometimes (usually after adding/editing/deleting a TreeCrownCondition option) the app will crash on the above lines with the error I posted at the beginning.

The error seems straightforward to fix, except that I'm only using one NSManagedObjectContext throughout the entirety of my app. Each new controller grabs it when it's loaded with the following code:

if(!managedObjectContext){
    managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

I couldn't find very much information about this error or how to resolve it, and I certainly didn't find anyone who'd had this problem without using multiple contexts.

I can only assume I somehow do have multiple contexts, but I can't see how that's possible. What am I missing?

Edit Heres the stack trace:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'condition' between objects in different contexts (source = <TreeCrown: 0x64b9f00> (entity: TreeCrown; id: 0x648db30 <x-coredata://6E17F271-7670-44EA-9901-5AB58DCA8AC7/TreeCrown/p3> ; data: {
    condition = "0x64e5c50 <x-coredata://6E17F271-7670-44EA-9901-5AB58DCA8AC7/TreeCrownCondition/p4>";
    images = "<relationship fault: 0x64d5e10 'images'>";
    recommendation = "0x64a5320 <x-coredata://6E17F271-7670-44EA-9901-5AB58DCA8AC7/TreeCrownRecommendation/p1>";
    tree = "0x6488f70 <x-coredata://6E17F271-7670-44EA-9901-5AB58DCA8AC7/AssessmentTree/p1>";
}) , destination = <TreeCrownCondition: 0xf218a40> (entity: TreeCrownCondition; id: 0xf215c20 <x-coredata://6E17F271-7670-44EA-9901-5AB58DCA8AC7/TreeCrownCondition/p2> ; data: <fault>))'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x029d5919 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x027ea5de objc_exception_throw + 47
    2   CoreData                            0x02461810 _PFManagedObject_coerceValueForKeyWithDescription + 1248
    3   CoreData                            0x02478245 _sharedIMPL_setvfk_core + 197
    4   CoreData                            0x0247bfe7 _svfk_0 + 39
    5   landscapes                          0x0000e569 -[AssessmentTreeCRViewController pickerView:didSelectRow:inComponent:] + 571
    6   UIKit                               0x004647aa -[UIPickerView _sendSelectionChangedForComponent:] + 100
    7   UIKit                               0x00602ed3 -[UIScroller _scrollAnimationEnded] + 130
    8   UIKit                               0x0050e792 -[UIAnimator stopAnimation:] + 467
    9   UIKit                               0x0050e557 -[UIAnimator(Static) _advance:] + 298
    10  GraphicsServices                    0x034c856d HeartbeatTimerCallback + 35
    11  CoreFoundation                      0x029b6d43 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
    12  CoreFoundation                      0x029b8384 __CFRunLoopDoTimer + 1364
    13  CoreFoundation                      0x02914d09 __CFRunLoopRun + 1817
    14  CoreFoundation                      0x02914280 CFRunLoopRunSpecific + 208
    15  CoreFoundation                      0x029141a1 CFRunLoopRunInMode + 97
    16  GraphicsServices                    0x034c52c8 GSEventRunModal + 217
    17  GraphicsServices                    0x034c538d GSEventRun + 115
    18  UIKit                               0x0047cb58 UIApplicationMain + 1160
    19  landscapes                          0x00001eb6 main + 104
    20  landscapes                          0x00001e45 start + 53
)
terminate called after throwing an instance of 'NSException'
A: 

I've seen weird errors like this are often due to a stale data store. Have you tried completely removing the app from the sim or device (e.g. tap-hold delete)? Do a clean build, then build and run.

Matt Long
I tried that, but at your suggestion I tried it again, only to receive the same error.
Evan Cordell
+2  A: 

How are you creating your Entities? If you are creating an entity without a NSManagedObjectContext it would produce the same error.

Update

From the look of your code I am guessing that what you are getting back out of the picker is not what you are expecting or unnecessarily casting to.

I would put a breakpoint on objc_throw_exception and duplicate the crash in the debugger. Once you do that then inspect the objects and I expect you will find that what you are getting out of the picker is not a NSManagedObject but something else.

Marcus S. Zarra
They're all created with a context. You can see the full code here: http://github.com/ecordell/landscapes/blob/master/Classes/AssessmentTreeCRViewController.m
Evan Cordell
As an aside; the casting you do in this code is unnecessary and should be removed for code clarity. For example `TreeOverallRecommendation *fc = (TreeOverallRecommendation *)[recommendationArray objectAtIndex:[recommendationPicker selectedRowInComponent:0]];` is an unnecessary cast. `-objectAtIndex:` like most methods in Objective-C return an `id` which does not require a cast.
Marcus S. Zarra
I have pulled down the source code. How do I duplicate the error?
Marcus S. Zarra
Ah, thanks, I'm new to objc.When you compile and run, go to Assessments, click on or add a record, then click "input" and click on one of the red or blue numbered buttons (overlaid on the tree). Then add a new record with the plus button, and then select different entries with the uipickerview. This almost always results in an error, sometimes I have to add, edit, or delete a couple times and then select again, though.
Evan Cordell
I am not able to duplicate the crash in the simulator. Can you perhaps show the stack trace of the crash? Show what line of code is causing the crash?
Marcus S. Zarra
I added the stack trace to my original post.
Evan Cordell