NSDate上的核心数据保存例外

时间:2012-07-18 17:27:30

标签: objective-c macos cocoa core-data osx-snow-leopard

我有这个accessDate字段,在数据模型中设置为日期类型。我在访问时使用object.accessDate = [NSDate date]更新accessDate。

它是一个多线程应用程序,我已经完成了2个实现,一个具有共享的NSManagedObjectContext和适当的锁,另一个具有多个上下文和适当的合并,两者都偶尔抛出这个异常。

我在流程环境中设置了NSZombieEnabled。我有点想法,所以我很高兴听到一些新的建议。

编辑:我忘了添加它只发生在Mac OS X 10.6上

例外是:

(gdb) po $rax
-[__NSCFDate longLongValue]: unrecognized selector sent to instance 0x16ddf3020

该对象看起来并不可疑:

(gdb) po 0x16ddf3020
2012-07-18 18:11:35 +0200
(gdb) po [0x16ddf3020 class]
__NSCFDate

和回溯:

(gdb) bt
#0  0x00007fff8973deea in objc_exception_throw ()
#1  0x00007fff803bc110 in -[NSObject(NSObject) doesNotRecognizeSelector:] ()
#2  0x00007fff803348ef in ___forwarding___ ()
#3  0x00007fff80330a38 in __forwarding_prep_0___ ()
#4  0x00007fff831ad540 in -[NSSQLiteConnection execute] ()
#5  0x00007fff831f8e85 in -[NSSQLiteConnection updateRow:] ()
#6  0x00007fff831f801b in -[NSSQLConnection performAdapterOperation:] ()
#7  0x00007fff831f7f50 in -[NSSQLConnection performAdapterOperations:] ()
#8  0x00007fff831f7acb in -[NSSQLCore _performChangesWithAdapterOps:] ()
#9  0x00007fff831f680b in -[NSSQLCore performChanges] ()
#10 0x00007fff831f1259 in -[NSSQLCore saveChanges:] ()
#11 0x00007fff831b4c8b in -[NSSQLCore executeRequest:withContext:] ()
#12 0x00007fff831b4051 in -[NSPersistentStoreCoordinator(_NSInternalMethods) executeRequest:withContext:] ()
#13 0x00007fff831e8123 in -[NSManagedObjectContext save:] ()

1 个答案:

答案 0 :(得分:0)

答案是“适当的锁定”毕竟不是真的。

我已将属性声明为

@property (nonatomic, retain) NSDate *accessDate;

并在实施文件中

@dynamic accessDate;

为了保证对属性的正确锁定我会想到

- (id)primitiveValueForKey:(NSString *)key
{
  [[self managedObjectContext] lock];
  id value = [super primitiveValueForKey:key];
  [[self managedObjectContext] unlock];
  return value;
}

就足够了,但实际上合成的Core Data属性根本不会调用primitiveValueForKey:,这是对我的误解,所以事实上访问没有被正确锁定。答案可能是合成的Core Data访问器锁定10.7上下文,而不是10.6上。

所以我通过手动重新实现访问器解决了我的问题:

- (NSDate *)accessDate
{
  [self willAccessValueForKey:@"accessDate"];
  NSDate *date = [self primitiveValueForKey:@"accessDate"];
  [self didAccessValueForKey:@"accessDate"];  

  return date;
}