如何在核心数据 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 子类具有一对多的无序关系。为了清楚起见,假设这两个子类是TeacherStudent,其中一个Teacher 可以有多个Student 对象,但每个Student 只分配给一个Teacher

我希望能够在 Student 添加到 Teacher 或从 Teacher 删除时触发通知,无论是因为 Student 只是简单地分配给 Teacher 或从 Teacher 分配,还是因为 @987654338 @ 已从 Core Data 中完全删除。

我尝试使用 KVO,但您似乎无法将观察者添加到 NSSetcount 属性 将观察者添加到 @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 子类导入核心数据?

如何使用更新的数据刷新 NSManagedObject - Core Data

ios核心数据:如何更改NSManagedObject而不将其保存到上下文中