-[ClassRoster controllerWillChangeContent:]: message sent to deallocated instance
I know these errors are very app-specific and almost always due to over-releasing an object. I just can't spot it and the debugging tips I have read haven't done the trick for me yet.
According to this debugging advice, my "offending object" was allocated in this code block (located in AddClass.m
):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 1) {
ClassRoster *classRoster = [[ClassRoster alloc] init];
classRoster.managedObjectContext = managedObjectContext;
classRoster.newClass = self.newClass;
classRoster.title = @"Class Roster";
[self.navigationController pushViewController:classRoster animated:YES];
[classRoster release];
}
}
However, I don't understand how the offending object could be from here. I believe I am appropriately releasing classRoster
and nothing else is being allocated.
The error message clearly indicates that the program was trying to update an object in my classRoster
TableViewController. This makes sense, because the crash occurred as I was trying to save an object in classRoster's detailViewController (AddStudent.m
) that gets pushed on when an object in classRoster
is selected.
To give the broader context of this problem, I am using Core Data and (as you can see from the above code) passing a single managedObjectContext
between views in order to edit and save a list of classes and their related class rosters. I am using [managedObjectContext rollback]
to cancel changes.
It might be worth mentioning that the save method inside of AddStudent.m updates the newly-created student object with strings entered by the user and then adds that student object to its parent class object via [class addStudentObject:student]
. The detailViewController (AddStudent.m
) is then popped with [delegate addStudent:self didFinishWithSave:YES]
. Upon returning to ClassRoster.m
, the managedObjectContext
is saved.
If you think my Core Data management might be the problem, just let me know what code you would like to see. This is my first app and consequently I have the joy of making lots of stupid mistakes!
UPDATE:
I have honed in on the sequence of actions that results in a crash. I will always crash with the error in my question's subject line if I do the following:
- Select an existing class object (push on its AddClass detailViewController)
- Select to view the class' roster
- Hit the back button to return to the class object detailView
- Select to view the class' roster again
- Select to add new student or select an existing student object
- Choose to save
The break line is marked by "BREAK >>" in the following stack trace:
0x01e8c2f0 <+0000> push %ebp
0x01e8c2f1 <+0001> mov %esp,%ebp
0x01e8c2f3 <+0003> push %edi
0x01e8c2f4 <+0004> push %esi
0x01e8c2f5 <+0005> push %ebx
0x01e8c2f6 <+0006> sub $0x5c,%esp
0x01e8c2f9 <+0009> call 0x1e8c2fe <___forwarding___+14>
0x01e8c2fe <+0014> pop %ebx
0x01e8c2ff <+0015> mov 0xc(%ebp),%esi
0x01e8c302 <+0018> test %esi,%esi
0x01e8c304 <+0020> je 0x1e8c620 <___forwarding___+816>
0x01e8c30a <+0026> mov 0x8(%ebp),%eax
0x01e8c30d <+0029> add $0x4,%eax
0x01e8c310 <+0032> mov 0x8(%ebp),%edx
0x01e8c313 <+0035> mov 0x4(%edx),%edx
0x01e8c316 <+0038> mov %edx,-0x30(%ebp)
0x01e8c319 <+0041> mov 0x4(%eax),%eax
0x01e8c31c <+0044> mov %eax,-0x2c(%ebp)
0x01e8c31f <+0047> mov -0x30(%ebp),%ecx
0x01e8c322 <+0050> mov %ecx,(%esp)
0x01e8c325 <+0053> call 0x1f0a11e <dyld_stub_object_getClass>
0x01e8c32a <开发者_C百科;+0058> mov %eax,(%esp)
0x01e8c32d <+0061> call 0x1f09e5a <dyld_stub_class_getName>
0x01e8c332 <+0066> mov %eax,-0x28(%ebp)
0x01e8c335 <+0069> movl $0xa,-0x34(%ebp)
0x01e8c33c <+0076> cld
0x01e8c33d <+0077> lea 0x73a30(%ebx),%edi
0x01e8c343 <+0083> mov %eax,%esi
0x01e8c345 <+0085> mov $0xa,%ecx
0x01e8c34a <+0090> repz cmpsb %es:(%edi),%ds:(%esi)
0x01e8c34c <+0092> mov $0x0,%eax
0x01e8c351 <+0097> je 0x1e8c35d <___forwarding___+109>
0x01e8c353 <+0099> movzbl -0x1(%esi),%eax
0x01e8c357 <+0103> movzbl -0x1(%edi),%ecx
0x01e8c35b <+0107> sub %ecx,%eax
0x01e8c35d <+0109> test %eax,%eax
0x01e8c35f <+0111> jne 0x1e8c3a7 <___forwarding___+183>
0x01e8c361 <+0113> mov 0x95d46(%ebx),%eax
0x01e8c367 <+0119> cmpb $0x0,(%eax)
0x01e8c36a <+0122> jne 0x1e8c680 <___forwarding___+912>
0x01e8c370 <+0128> mov -0x2c(%ebp),%edx
0x01e8c373 <+0131> mov %edx,(%esp)
0x01e8c376 <+0134> call 0x1f0a214 <dyld_stub_sel_getName>
0x01e8c37b <+0139> mov -0x30(%ebp),%ecx
0x01e8c37e <+0142> mov %ecx,0x10(%esp)
0x01e8c382 <+0146> mov %eax,0xc(%esp)
0x01e8c386 <+0150> mov -0x28(%ebp),%eax
0x01e8c389 <+0153> add $0xa,%eax
0x01e8c38c <+0156> mov %eax,0x8(%esp)
0x01e8c390 <+0160> lea 0x9d822(%ebx),%eax
0x01e8c396 <+0166> mov %eax,0x4(%esp)
0x01e8c39a <+0170> movl $0x3,(%esp)
0x01e8c3a1 <+0177> call 0x1eb3040 <CFLog>
0x01e8c3a6 <+0182> int3
BREAK >> 0x01e8c3a7 <+0183> movl $0x11,-0x38(%ebp)
0x01e8c3ae <+0190> cld
0x01e8c3af <+0191> lea 0x79590(%ebx),%edi
0x01e8c3b5 <+0197> mov -0x28(%ebp),%esi
0x01e8c3b8 <+0200> mov $0x11,%ecx
0x01e8c3bd <+0205> repz cmpsb %es:(%edi),%ds:(%esi)
0x01e8c3bf <+0207> mov $0x0,%eax
0x01e8c3c4 <+0212> je 0x1e8c3d0 <___forwarding___+224>
0x01e8c3c6 <+0214> movzbl -0x1(%esi),%eax
0x01e8c3ca <+0218> movzbl -0x1(%edi),%ecx
0x01e8c3ce <+0222> sub %ecx,%eax
0x01e8c3d0 <+0224> mov -0x30(%ebp),%edx
0x01e8c3d3 <+0227> mov %edx,-0x24(%ebp)
0x01e8c3d6 <+0230> test %eax,%eax
0x01e8c3d8 <+0232> jne 0x1e8c3e0 <___forwarding___+240>
0x01e8c3da <+0234> mov 0x4(%edx),%ecx
0x01e8c3dd <+0237> mov %ecx,-0x24(%ebp)
0x01e8c3e0 <+0240> mov 0xa1dbe(%ebx),%esi
0x01e8c3e6 <+0246> mov -0x24(%ebp),%eax
0x01e8c3e9 <+0249> mov %eax,(%esp)
0x01e8c3ec <+0252> call 0x1f0a11e <dyld_stub_object_getClass>
0x01e8c3f1 <+0257> mov %esi,0x4(%esp)
0x01e8c3f5 <+0261> mov %eax,(%esp)
0x01e8c3f8 <+0264> call 0x1f09e72 <dyld_stub_class_respondsToSelector>
0x01e8c3fd <+0269> test %al,%al
0x01e8c3ff <+0271> je 0x1e8c580 <___forwarding___+656>
0x01e8c405 <+0277> mov -0x2c(%ebp),%edx
0x01e8c408 <+0280> mov %edx,0x8(%esp)
0x01e8c40c <+0284> mov %esi,0x4(%esp)
0x01e8c410 <+0288> mov -0x24(%ebp),%ecx
0x01e8c413 <+0291> mov %ecx,(%esp)
0x01e8c416 <+0294> call 0x1f0a0ee <dyld_stub_objc_msgSend>
0x01e8c41b <+0299> mov %eax,-0x20(%ebp)
0x01e8c41e <+0302> mov %eax,-0x1c(%ebp)
0x01e8c421 <+0305> test %eax,%eax
0x01e8c423 <+0307> je 0x1e8c5ac <___forwarding___+700>
0x01e8c429 <+0313> mov 0xa1df6(%ebx),%eax
0x01e8c42f <+0319> mov %eax,0x4(%esp)
0x01e8c433 <+0323> mov -0x1c(%ebp),%edx
0x01e8c436 <+0326> mov %edx,(%esp)
0x01e8c439 <+0329> call 0x1f0a0ee <dyld_stub_objc_msgSend>
0x01e8c43e <+0334> mov (%eax),%edx
0x01e8c440 <+0336> mov 0x18(%edx),%eax
0x01e8c443 <+0339> shr $0x16,%eax
0x01e8c446 <+0342> and $0x1,%eax
0x01e8c449 <+0345> cmp 0xc(%ebp),%eax
0x01e8c44c <+0348> je 0x1e8c498 <___forwarding___+424>
0x01e8c44e <+0350> lea 0x6eaee(%ebx),%eax
0x01e8c454 <+0356> lea 0x7979f(%ebx),%esi
0x01e8c45a <+0362> mov 0xc(%ebp),%ecx
0x01e8c45d <+0365> test %ecx,%ecx
0x01e8c45f <+0367> mov %eax,%edi
0x01e8c461 <+0369> cmove %esi,%edi
0x01e8c464 <+0372> testb $0x40,0x1a(%edx)
0x01e8c468 <+0376> cmovne %eax,%esi
0x01e8c46b <+0379> mov -0x2c(%ebp),%ecx
0x01e8c46e <+0382> mov %ecx,(%esp)
0x01e8c471 <+0385> call 0x1f0a214 <dyld_stub_sel_getName>
0x01e8c476 <+0390> mov %edi,0x10(%esp)
0x01e8c47a <+0394> mov %esi,0xc(%esp)
0x01e8c47e <+0398> mov %eax,0x8(%esp)
0x01e8c482 <+0402> lea 0x9d852(%ebx),%eax
0x01e8c488 <+0408> mov %eax,0x4(%esp)
0x01e8c48c <+0412> movl $0x4,(%esp)
0x01e8c493 <+0419> call 0x1eb3040 <CFLog>
0x01e8c498 <+0424> mov -0x20(%ebp),%eax
0x01e8c49b <+0427> mov %eax,0x8(%esp)
0x01e8c49f <+0431> mov 0xa1dba(%ebx),%eax
0x01e8c4a5 <+0437> mov %eax,0x4(%esp)
0x01e8c4a9 <+0441> mov 0xa1e76(%ebx),%eax
0x01e8c4af <+0447> mov %eax,(%esp)
0x01e8c4b2 <+0450> call 0x1f0a0ee <dyld_stub_objc_msgSend>
0x01e8c4b7 <+0455> mov %eax,%edi
0x01e8c4b9 <+0457> mov 0xa1dde(%ebx),%eax
Here's what's more likely:
- Something does
instanceVariable = [NSArray arrayWithObjects:..., nil];
- The NSArray was not retained, so it gets released at the end of the run loop.
- Something taps the row. The NSArray's memory gets reused to make your ClassRoster object.
- You navigate out of ClassRoster, and it gets released and dealloced.
- Something tries to access instanceVariable. It points to the memory that used to be a NSArray, but has now been overwritten by ClassRoster.
Try setting the environment variable NSZombieEnabled=YES (in Project -> Edit Active Executable). You can also set NSDeallocateZombies=NO, but AIUI that's the default.
Turn it off once you're finished debugging.
EDIT: Oops (I should've realized you had zombies on, and looked at the method name).
If you run it in the debugger (you might need breakpoints active), it should stop at the thing that called controllerWillChangeContent:. Perhaps your ClassRoster is being set as the delegate for something, and is getting a delegate callback after it's been dealloced? I always set the relevant delegates to nil in dealloc to prevent problems like this.
I don't think you have over-released the instance.
To me, it looks like the deallocated instance is of some other class but receives a message from ClassRoaster
.
Can you post the error message and the stack trace from the moment you app crashes?
'Illegal attempt to establish a relationship 'myClass' between objects in different contexts'
That line describes the issue. You are probably using code from an Apple example that has you building more than one NSManagedObjectContext
correct? Perhaps the code suggested to create a second one so that you can easily cancel out of an edit or some such?
That is your problem. You are trying to connect two objects that are in two different NSManagedObjectContext
instances. Consider each NSManagedObjectContext
to be a sandbox and you can't mix them.
However, you do not need to have more than one NSManagedObjectContext
. The example that does that is a very bad example. A single NSManagedObjectContext
is more than sufficient for any single threaded application. Remove the second NSManagedObjectContext
from your application and this issue will go away.
Update
I found the error. You cannot create a NSManagedObject
with -init
. That is not the designated initializer for an NSManagedObject
. You must either create it with
-initWithEntity: insertIntoManagedObjectContext:
or use the class method
+[NSEntityDescription insertNewObjectForEntityForName: inManagedObjectContext]
Those are the only two valid ways to create a new NSManagedObject
.]
Update
I strongly suggest you use better naming conventions, ClassRosterViewController
is far more descriptive. ClassRoster
really sounds like data object.
My original assumption still stands, somewhere, somehow you are trying to connect two NSManagedObject
instances that do not belong to the same NSManagedObjectContext
. Either you have two instances of NSManagedObjectContext
or you are creating a NSManagedObject
without an associated NSManagedObjectContext
.
However, my responses are based around the error message that is in your question. Where are you seeing the error that is in your title. Can you paste that stack trace as well?
just had the same problem the problem was because i had released the delegate instead of setting it to nil
good luck!
精彩评论