-[NSManagedObject willTurnIntoFault] 是不是禁用 KVO 通知?

Posted

技术标签:

【中文标题】-[NSManagedObject willTurnIntoFault] 是不是禁用 KVO 通知?【英文标题】:Does -[NSManagedObject willTurnIntoFault] disable KVO notifications?-[NSManagedObject willTurnIntoFault] 是否禁用 KVO 通知? 【发布时间】:2011-01-19 16:09:26 【问题描述】:

我有一个 NSManagedObject(人),它有几个观察者注册到一个嵌套的非托管属性(person.address.street,地址是非托管的,即未在核心数据中定义)。当托管对象出现故障时,我调用

person.address = nil

在 willTurnIntoFault 中清除我的非托管财产。但是,KVO 不会删除它为地址注册的观察者以获取有关“街道”更改的通知,尽管地址是 KVO 兼容的。地址被解除分配,我收到一条警告说它仍然注册了观察者。

我能弄清楚的唯一原因是 willTurnIntoFault 禁用了 KVO 通知。是这样吗?有没有办法解决这个问题。

谢谢, 乔辰

【问题讨论】:

【参考方案1】:

乔辰,

我在托管对象上下文合并处理中看到了同样的行为(通过 mergeChangesFromContextDidSaveNotification:)。对于合并用户信息中的“更新”对象,核心数据会导致“本地”上下文对象出错,然后针对“远程”上下文对象执行合并。

如果作为 didTurnIntoFault: 处理的一部分,我释放了我的非托管属性(这非常简单并且绝对符合 KVO),则会出现错误。有趣的是,它似乎只发生在“嵌套”的非托管属性中。我有许多其他非托管属性作为我的托管对象的一部分,它们是简单对象(NSNumber、NSString 等),这些可以作为 didTurnIntoFault 的一部分释放:处理没有任何问题。只有在非托管属性中观察到 >= 2 层深度的属性时,我才会看到问题。

我不确定您是否找到了解决方案(我很想听听您在这方面的进展情况),但我找到了解决方法。我将非托管属性分配在故障对象中,仅在 prepareForDeletion 期间释放它。

-(void) performInventoryItemObjectSetup

    if ([self unitsManager] == nil) 
        [self setUnitsManager:[[[BTUnitsManager alloc] init] autorelease]];
    
    ...


-(void) performInventoryItemObjectCleanup

    ...


/********************/

-(void) awakeFromInsert

    //NSLog(@"InventoryItem: awakeFromInsert");
    [super awakeFromInsert];
    [self performInventoryItemObjectSetup];


-(void) awakeFromSnapshotEvents:(NSSnapshotEventType)flags

    //NSLog(@"InventoryItem: awakeFromSnapshotEvents: 0x%lx", flags);

    [super awakeFromSnapshotEvents:flags];

    if (flags & NSSnapshotEventUndoDeletion) 
        [self performInventoryItemObjectSetup];
    


-(void) awakeFromFetch

    //NSLog(@"InventoryItem: awakeFromFetch");
    [super awakeFromFetch];
    [self performInventoryItemObjectSetup];


-(void) didTurnIntoFault

    //NSLog(@"InventoryItem: didTurnIntoFault");
    [self performInventoryItemObjectCleanup];
    [super didTurnIntoFault];



-(void) prepareForDeletion

    NSLog(@"InventoryItem: prepareForDeletion");
    [self setUnitsManager:nil];
    [super prepareForDeletion];

我怀疑随着越来越多的 Core Data 应用程序发布支持 iCloud,这需要这种合并作为 NSPersistentStoreDidImportUbiquitousContentChangesNotification 处理的一部分,会有更多人遇到这个问题。要么这样,要么我们会发现我们做错了什么:-)。

干杯, 迈克尔。

【讨论】:

刚刚意识到我还没有尝试将解决方法放在 prepareForDeletion 中。我明天试试。如果它也有效,我会将其归类为比覆盖 dealloc 更好的解决方法。 使用 prepareForDeletion 效果很好,是解决此问题的更好解决方案。【参考方案2】:

您可以使用http://developer.apple.com/library/mac/#releasenotes/Cocoa/FoundationOlder.html 中描述的技术 为避免此错误,您可以在绑定中使用不同的键路径,其中将包括实体,并符合 KVO。 请查看“支持调试不良 KVO 合规性”和“修复一种不良 KVO 合规性的建议”说明。

【讨论】:

您在文档中提到了哪种技术?除了可能使用 setKeys:triggerChangeNotificationsForDependentKey: 之外,我在其中找不到任何与此问题相关的内容,但这已被弃用。

以上是关于-[NSManagedObject willTurnIntoFault] 是不是禁用 KVO 通知?的主要内容,如果未能解决你的问题,请参考以下文章

NSManagedObject 故障/无法获得由 NSManagedObject 处理的“原始”对象

NSManagedObject - NSSet 被删除?

如何根据现有的 NSManagedObject 值在 NSManagedObject 派生类中设置默认值?

属性作为“当前 NSManagedObject”的视图控制器中的 NSManagedObject

创建新的 NSManagedObject 并将其分配给新的 NSManagedObject *有时*会失败

将 NSManagedObject 与另一个 NSManagedContext(多线程)中的“相同”NSManagedObject 合并