foo
のサブクラスで、フィールドのカスタムセッターメソッドを記述する必要があります(NSManagedObject
と呼びます)。 foo
はデータモデルで定義されており、Xcodeは.hおよび.mファイルにそれぞれ自動生成された@property
および@dynamic
フィールドを持っています。
このようにセッターを書くと:
- (void)setFoo: (NSObject *)inFoo {
[super setFoo: inFoo];
[self updateStuff];
}
super
の呼び出しでコンパイラの警告が表示されます。
または、これを行う場合:
- (void)setFoo: (NSObject *)inFoo {
[super setValue: inFoo forKey: inFoo];
[self updateStuff];
}
その後、無限ループに陥ります。
NSManagedObjectのサブクラスのカスタムセッターを作成する正しいアプローチは何ですか?
.mで、NSManagedObjectプロパティを(KVOを壊さずに)オーバーライドするAppleの方法):
@interface Transaction (DynamicAccessors)
- (void)managedObjectOriginal_setDate:(NSDate *)date;
@end
@implementation Transaction
@dynamic date;
- (void)setDate:(NSDate *)date
{
// invoke the dynamic implementation of setDate (calls the willChange/didChange for you)
[self managedObjectOriginal_setDate:(NSString *)date;
// your custom code
}
managedObjectOriginal_propertyName
は組み込みのmagicメソッドで、定義を追加するだけです。このページの下部にあるように macOS 10.12、iOS 10.0、tvOS 10.0、およびwatchOS 3.0のコアデータの新機能
ドキュメント によると、次のようになります。
- (void) setFoo:(NSObject *)inFoo {
[self willChangeValueForKey:@"foo"];
[self setPrimitiveValue:inFoo forKey:@"foo"];
[self didChangeValueForKey:@"foo"];
}
もちろん、これはNSManagedObjects
が属性としてNSNumbers
、NSDates
、NSDatas
、およびNSStrings
のみを必要とするという事実を無視します。
ただし、これは最善のアプローチではない場合があります。 foo
プロパティの値が変更されたときに何かが発生するようにしたいので、なぜ Key Value Observing でそれを観察しないのですか?この場合、「KVOが道を行く」ように聞こえます。
Photo : NSManagedObject
のid
属性でKVOを実行する方法は次のとおりです。写真のIDが変更された場合は、新しい写真をダウンロードします。
#pragma mark NSManagedObject
- (void)awakeFromInsert {
[self observePhotoId];
}
- (void)awakeFromFetch {
[self observePhotoId];
}
- (void)observePhotoId {
[self addObserver:self forKeyPath:@"id"
options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change
context:(void *)context {
if ([keyPath isEqualToString:@"id"]) {
NSString *oldValue = [change objectForKey:NSKeyValueChangeOldKey];
NSString *newValue = [change objectForKey:NSKeyValueChangeNewKey];
if (![newValue isEqualToString:oldValue]) {
[self handleIdChange];
}
}
}
- (void)willTurnIntoFault {
[self removeObserver:self forKeyPath:@"id"];
}
#pragma mark Photo
- (void)handleIdChange {
// Implemented by subclasses, but defined here to hide warnings.
// [self download]; // example implementation
}
私はわずかな間違いがあると思う:使用
[self setPrimitiveValue:inFoo forKey:@"foo"];
の代わりに
[self setPrimitiveFoo:inFoo];
これは私のために働く。
1-n(およびn-mと仮定)の関係を行う方法は次のとおりです。
関係名が「学校」と呼ばれるオブジェクトの「学生」と呼ばれると仮定しましょう。
最初に、NSMutableSetのプリミティブアクセサーメソッドを定義する必要があります。 Xcodeはこれらを自動的に生成しません。
@interface School(PrimitiveAccessors)
- (NSMutableSet *)primitiveStudents;
@end
次に、アクセサメソッドを定義できます。ここで、セッターをオーバーライドします。
- (void)addStudentsObject:(Student *)student
{
NSSet *changedObjects = [[NSSet alloc] initWithObjects:&student count:1];
[self willChangeValueForKey:@"students"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects];
[[self primitiveStudents] addObject:value];
[self didChangeValueForKey:@"students"
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects];
}