如何在核心数据 NSManagedObject 关系的 NSSet 中添加或删除项目时触发通知?
Posted
技术标签:
【中文标题】如何在核心数据 NSManagedObject 关系的 NSSet 中添加或删除项目时触发通知?【英文标题】:How to trigger notifications when item added to or removed from Core Data NSManagedObject relationship's NSSet? 【发布时间】:2015-03-31 02:10:29 【问题描述】:每当在自定义NSManagedObject
子类中向一对多关系/NSSet
添加或删除项目时,触发NSNotification
的正确方法是什么?
我有一个自定义的 NSManagedObject
子类,它与另一个 NSManagedObject
子类具有一对多的无序关系。为了清楚起见,假设这两个子类是Teacher
和Student
,其中一个Teacher
可以有多个Student
对象,但每个Student
只分配给一个Teacher
。
我希望能够在 Student
添加到 Teacher
或从 Teacher
删除时触发通知,无论是因为 Student
只是简单地分配给 Teacher
或从 Teacher
分配,还是因为 @987654338 @ 已从 Core Data 中完全删除。
我尝试使用 KVO,但您似乎无法将观察者添加到 将观察者添加到 NSSet
的 count
属性@dynamic
属性。此外,我尝试按照Apple's documentation 中的说明实现我自己的自定义多对多访问器方法,但在测试中似乎从未调用过我的自定义访问器方法。如果我的实现有问题,下面是我在Teacher
中的实现方式:
@implementation Teacher
@dynamic students;
- (void)addStudentsObject:(Student *)value
NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
[self willChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects];
[[self primitiveStudents] addObject:value];
[self didChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:changedObjects];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TEACHER_STUDENT_WAS_ADDED object:self];
- (void)removeStudentsObject:(Student *)value
NSSet *changedObjects = [[NSSet alloc] initWithObjects:&value count:1];
[self willChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:changedObjects];
[[self primitiveStudents] removeObject:value];
[self didChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:changedObjects];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TEACHER_STUDENT_WAS_REMOVED object:self];
- (void)addStudents:(NSSet *)values
[self willChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:values];
[[self primitiveStudents] unionSet:values];
[self didChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueUnionSetMutation
usingObjects:values];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TEACHER_STUDENTS_WERE_ADDED object:self];
- (void)removeStudents:(NSSet *)values
[self willChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:values];
[[self primitiveStudents] minusSet:values];
[self didChangeValueForKey:NSStringFromSelector(@selector(students))
withSetMutation:NSKeyValueMinusSetMutation
usingObjects:values];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TEACHER_STUDENTS_WERE_REMOVED object:self];
...
@end
【问题讨论】:
我相信您只需要覆盖setStudents
和访问器,在使用primitiveStudents
后调用setPrimitiveStudents
来对两组进行增量。您重新实现的文档不是 students
属性的标准访问器。以指定和便利初始化器的方式将它们视为便利访问器。您已确保它们与 KVO 兼容,但您尚未确保其他代码使用它们。另外,如果你想使用 KVO,你必须 KVO 观察 students
键路径,你可以在该代码中获取旧集和新集。
如何覆盖setStudents
及其访问器?我在developer.apple.com/library/mac/documentation/Cocoa/Conceptual/… 中看到了“自定义原始访问器方法”部分,但不知道如何实现它,因为我不知道您在哪里定义了nonCompliantKVCivar
。
错字。该注释中应省略“和”。 setStudents
是学生属性的设置器访问器。 -(void) setStudents:(NSSet*)students [self willChangeValueForKey:@"students"]; [self setPrimitiveValue:students forKey:@"students"]; [self didChangeValueForKey:@"students"];
尝试在其中插入您的通知。或者,就像我说的,在 students
键路径上使用 KVO。无论如何,您实现的访问器不会被任何标准控制器使用。第三个选项是 MOC 的更改通知。
谢谢!您可以将此添加为答案吗?
【参考方案1】:
事实证明,您用作参考的Apple Docs 中的花哨访问器示例实际上并不是关系的所有访问器所有。它们是额外的便利访问器,您可以根据需要实现它们。但是因为您试图通过覆盖所有设置器(或任何您想调用的变异访问器)来插入代码,所以您还需要覆盖最基本的设置器。
对多关系最基本的访问器是整个关系的NSSet
对象的setter 和getter。在你的情况下,- (NSSet*) students
和 - (void) setStudents:(NSSet*)students
。
因此,您的通知至少需要发布到setStudents
:
-(void) setStudents:(NSSet*)students
[self willChangeValueForKey:@"students"];
[self setPrimitiveValue:students forKey:@"students"];
[self didChangeValueForKey:@"students"];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_TEACHER_STUDENTS_WERE_ADDED object:self];
那是默认使用的setter。
【讨论】:
以上是关于如何在核心数据 NSManagedObject 关系的 NSSet 中添加或删除项目时触发通知?的主要内容,如果未能解决你的问题,请参考以下文章
如何创建核心数据 NSManagedObject 的独立实例 - 非托管
如何在不复制目标 NSManagedObject 的情况下将目标 NSManagedObject 添加到另一个具有反向多对多核心数据关系的对象?
您如何获得一个新的核心数据实体属性以反映在该实体的 NSManagedObject 中?
如何将 NSManagedObject 的 NSKeyedUnarchive 子类导入核心数据?