0

データモデルで日付型として設定されたこのaccessDateフィールドがあります。アクセスするときにaccessDateを更新してobject.accessDate = [NSDate date]います。

これはマルチスレッド アプリケーションであり、2 つの実装を行いました。1 つは共有 NSManagedObjectContext と適切なロックを使用し、もう 1 つは複数のコンテキストと適切なマージを使用し、どちらも散発的にこの例外をスローします。

プロセス環境に 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:] ()
4

1 に答える 1

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;
}
于 2012-07-20T08:36:32.450 に答える