我需要在我的foo
子类中为字段编写自定义setter方法(我们称之为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的子类编写自定义setter的正确方法是什么?
答案 0 :(得分:102)
根据the documentation,它是:
- (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是要走的路”。
答案 1 :(得分:19)
以下是我在id
的{{1}}属性上执行KVO的方式。如果照片的ID发生变化,请下载新照片。
Photo : NSManagedObject
答案 2 :(得分:17)
我认为有一个小错误: 使用
[self setPrimitiveValue:inFoo forKey:@"foo"];
而不是
[self setPrimitiveFoo:inFoo];
这适合我。
答案 3 :(得分:6)
以下是在.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 方法,您只需添加其定义即可。如本页底部所示What's New in Core Data in macOS 10.12, iOS 10.0, tvOS 10.0, and watchOS 3.0
答案 4 :(得分:1)
有一个非常方便的 Xcode Snippets 菜单(Xcode 12 右上角有一个 + 按钮),其中包含用于覆盖许多常见 Core Data 代码的很棒的片段,包括用于对象的 KVO 兼容访问器-类型(getter + setter)。
答案 5 :(得分:0)
这里是你如何做到1-n(我假设n-m)关系:
让我们假设关系名称被称为"学生"在一个名为" School"。
的对象中首先,您需要为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];
}