我在一个简单的Core Data项目中崩溃了。
我使用Core Data创建了一个新的空iPhone项目。两个实体被添加到数据模型中,它们之间具有一对一的反向关系。两者都有自动生成的NSManagedObject子类。实体名称和类都设置在两者上。
DBMove
attribute: moveValue:Integer16
relationship: newPosition -> DBPosition (inverse: move)
DBPosition
attribute: positionValue:Integer16
relationship: move -> DBMove (inverse: newPosition)
有一个自定义视图控制器可以创建DBMove和DBPosition。然后它设置它们之间的反比关系并保存它。从app delegate中检索托管对象上下文;我认为这是安全的,因为[NSThread isMultiThreaded]返回false。
- (void)newEntries
{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext;
DBPosition *newPos = [NSEntityDescription
insertNewObjectForEntityForName:@"DBPosition"
inManagedObjectContext:context];
newPos.positionValue = [NSNumber numberWithInt:5];
DBMove *newMove = [NSEntityDescription
insertNewObjectForEntityForName:@"DBMove"
inManagedObjectContext:context];
newMove.moveValue = [NSNumber numberWithInt:2];
newPos.move = newMove;
NSError *error;
if (![context save:&error]) {
NSLog(@"Save error: %@", [error localizedDescription]);
}
}
视图控制器然后提取所有DBMoves。他们的Integer16属性按预期输出。 [编辑] 访问该关系会导致main :: @ autoreleasepool中的EXC_BAD_ACCESS在循环通过所有获取结果后的某个时间发生。崩溃之前,以前程序中数据库中DBMove和DBPosition的所有条目都运行正确,然后是来自我的ViewController init的NSLogs;崩溃似乎延迟了。它大约每5个程序运行中就有4个出现。 [结束编辑]
- (void)printMoves
{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = appDelegate.managedObjectContext;
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"DBMove"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (DBMove *move in fetchedObjects) {
DBPosition *newPos = move.newPosition; // <--- all's well without this reference!
NSLog(@"Move : %d", [move.moveValue intValue]);
NSLog(@"Position : %d", [newPos.positionValue intValue]);
}
}
NSZombieEnabled = YES会导致程序无误地运行并打印预期值。在整个执行过程中,我的上下文似乎是相同的。
这是堆栈跟踪:
#0 0x018300b2 in objc_msgSend ()
#1 0x00256ffc in -[_CDSnapshot dealloc] ()
#2 0x0025573d in -[_CDSnapshot release] ()
#3 0x00260384 in -[NSManagedObject(_NSInternalMethods) _clearRawPropertiesWithHint:] ()
#4 0x0026018b in -[NSFaultHandler turnObject:intoFaultWithContext:] ()
#5 0x002607ba in -[NSManagedObject dealloc] ()
#6 0x00257b88 in -[_PFManagedObjectReferenceQueue _processReferenceQueue:] ()
#7 0x00232fe1 in _performRunLoopAction ()
#8 0x01a654ce in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#9 0x01a6541f in __CFRunLoopDoObservers ()
#10 0x01a43344 in __CFRunLoopRun ()
#11 0x01a42ac3 in CFRunLoopRunSpecific ()
#12 0x01a428db in CFRunLoopRunInMode ()
#13 0x038fe9e2 in GSEventRunModal ()
#14 0x038fe809 in GSEventRun ()
#15 0x0058ed3b in UIApplicationMain ()
#16 0x0000396d in main at /Users/brian/devel/test2-CoreData/test2-CoreData/main.m:16
当我检查空新项目中的“核心数据”时,所有核心数据设置均来自标准包含。
据推测,我过度释放了一个托管对象,但在哪里?
答案 0 :(得分:9)
使用“new”开始属性newPosition
是个问题!它被翻译成一个带有名为“newPosition”的存取器的属性,Transitioning to ARC Release Notes中禁止使用该属性:
为了允许与手动保留释放代码进行互操作,ARC强制执行 方法命名约束:
您无法为访问者提供以new开头的名称。这反过来 意味着你不能,例如,声明一个名字的属性 除非您指定不同的getter,否则以new开头:
// Won't work: @property NSString *newTitle; // Works: @property (getter=theNewTitle) NSString *newTitle;
可以像示例中那样编写自定义getter,但是选择更好的名称并继续使用内置工具生成类文件要容易得多。
请注意,编译器在使用@synthesize时会捕获此错误,但不会在@dynamic中捕获此错误,如在自动生成的NSManagedObject类中使用的那样。