A Day In The Life

とあるプログラマの備忘録

NSManagedObjectでTo-Many関連を使用したときにコードの自動生成がされないバグの解決方法

Core Data の NSManagedObject クラスで以下のように To-Many(One-To-Many) 関連を使ったときにコードの自動生成をすると実装コードが生成されない場合があります。
one-to-many関連
通常の To-Many 関連では問題が起こらないのですが以下のように Ordered(順序) を指定してから NSManagedObject クラスのサブクラスの自動生成をすると実装コード(.m ファイルのコード)の一部が生成されません。
Orderedにチェックを入れる
これは Xcode のバグみたいです。最新の Xcode 4.6.1 でも発生しています。
自動生成されないコードはプログラマ自身が実装する必要があります。以下は Transaction(取引) クラスと Journal(仕訳明細) クラスに Ordered の To-Many 関連を設定する場合のコードの実装例です。

#import "Transaction.h"
#import "Journal.h"

@implementation Transaction

@dynamic abstract;
@dynamic date;
@dynamic entrepreneurNumber;
@dynamic journals;

static NSString *const kItemsKey = @"journals";

- (void)insertObject:(Journal *)value inJournalsAtIndex:(NSUInteger)idx
{
  NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
  [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  [tmpOrderedSet insertObject:value atIndex:idx];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)removeObjectFromJournalsAtIndex:(NSUInteger)idx
{
  NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
  [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  [tmpOrderedSet removeObjectAtIndex:idx];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)insertJournals:(NSArray *)values atIndexes:(NSIndexSet *)indexes
{
  [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  [tmpOrderedSet insertObjects:values atIndexes:indexes];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)removeJournalsAtIndexes:(NSIndexSet *)indexes
{
  [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  [tmpOrderedSet removeObjectsAtIndexes:indexes];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)replaceObjectInJournalsAtIndex:(NSUInteger)idx withObject:(Journal *)value
{
  NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
  [self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  [tmpOrderedSet replaceObjectAtIndex:idx withObject:value];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)replaceJournalsAtIndexes:(NSIndexSet *)indexes withJournals:(NSArray *)values
{
  [self willChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  [tmpOrderedSet replaceObjectsAtIndexes:indexes withObjects:values];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeReplacement valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)addJournalsObject:(Journal *)value
{
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  NSUInteger idx = [tmpOrderedSet count];
  NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
  [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
  [tmpOrderedSet addObject:value];
  [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
  [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
}
- (void)removeJournalsObject:(Journal *)value
{
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  NSUInteger idx = [tmpOrderedSet indexOfObject:value];
  if (idx != NSNotFound) {
    NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];
    [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
    [tmpOrderedSet removeObject:value];
    [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
    [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
  }
}
- (void)addJournals:(NSOrderedSet *)values
{
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
  NSUInteger valuesCount = [values count];
  NSUInteger objectsCount = [tmpOrderedSet count];
  for (NSUInteger i = 0; i < valuesCount; ++i) {
    [indexes addIndex:(objectsCount + i)];
  }
  if (valuesCount > 0) {
    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
    [tmpOrderedSet addObjectsFromArray:[values array]];
    [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:kItemsKey];
  }
}
- (void)removeJournals:(NSOrderedSet *)values
{
  NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:kItemsKey]];
  NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
  for (id value in values) {
    NSUInteger idx = [tmpOrderedSet indexOfObject:value];
    if (idx != NSNotFound) {
      [indexes addIndex:idx];
    }
  }
  if ([indexes count] > 0) {
    [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
    [tmpOrderedSet removeObjectsAtIndexes:indexes];
    [self setPrimitiveValue:tmpOrderedSet forKey:kItemsKey];
    [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:kItemsKey];
  }
}
@end

Xcode の次のバージョンで修正されると良いのですが...。

関連書籍

Core Dataに関する基礎情報はこちらの本を参考にしてください。