OStack程序员社区-中国程序员成长平台

标题: ios - KVO 和 Core Data - 自观察托管对象 [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-13 08:23
标题: ios - KVO 和 Core Data - 自观察托管对象

我认为这个问题很简单也很常见,但我仍然不明白为什么它不起作用。让我暴露上下文:

假设我有一个不错的核心数据模型,其中包含一个名为 Document 的实体。该文档有类型、日期、编号和版本...例如,类型:D,日期:17-10-2015,编号:24 和版本 3。 本文档具有使用这四个值计算的标识符:D20151017-24-R03

这样的文档会很多,我必须通过它的 Identifier 来搜索它们,而且我也会使用很多 NSFetchedResultsController。所以暂时的可能性就出来了。

这就是我所做的。先注册观察四个相关属性:

- (instancetype)initWithEntityNSEntityDescription *)entity insertIntoManagedObjectContextNSManagedObjectContext *)context {
    self = [super initWithEntity:entity insertIntoManagedObjectContext:context];

    if (self) {
        [self addObserver:self forKeyPath:_Property(documentTypeRaw) options:0 context:KVODocumentIdContext];
        [self addObserver:self forKeyPath:_Property(date) options:0 context:KVODocumentIdContext];
        [self addObserver:self forKeyPath:_Property(number) options:0 context:KVODocumentIdContext];
        [self addObserver:self forKeyPath:_Property(version) options:0 context:KVODocumentIdContext];
    }

    return self;
}

然后,在释放时注销:

- (void)dealloc {
    [self removeObserver:self forKeyPath:_Property(documentTypeRaw) context:KVODocumentIdContext];
    [self removeObserver:self forKeyPath:_Property(date) context:KVODocumentIdContext];
    [self removeObserver:self forKeyPath:_Property(number) context:KVODocumentIdContext];
    [self removeObserver:self forKeyPath:_Property(version) context:KVODocumentIdContext];
}

最后,管理通知:

- (void) observeValueForKeyPathNSString *)keyPath ofObjectid)object changeNSDictionary *)change contextvoid *)context {
    if (context == KVODocumentIdContext) {
        [self updateDocumentId];
    }
    else {
        [super observeValueForKeyPath:keyPath ofObjectbject change:change context:context];
    }
}

就在这里updateDocumentId:

- (void) updateDocumentId {
    NSString * prefix = [self documentTypePrefix:self.documentTypeRaw];
    NSString * date = [self.date documentIdFormat];
    NSString * number = [NSString stringWithFormat"%.2d",[self.number shortValue]];
    NSString * version = [self.version isEqualToNumber0]?@"":[NSString stringWithFormat"-R%.2d",[self.version shortValue]];

    self.documentId = [NSString stringWithFormat"%@%@-%@%@",prefix,date,number,version];
}

对我来说,这应该是完美的......但是......它没有......

我有一个很好的:

failed: caught "NSInternalInconsistencyException", "<MBSDocument: 0x7fd9dbb45f40> (entity: MBSDocument; id: 0x7fd9dbb3cd00 <x-coredata:///MBSDocument/tB55CB581-AEC0-4211-A78A-7C48377BACC2612> ; data:
...
An -observeValueForKeyPathfObject:change:context: message was received but not handled.
Key path: date
Observed object: <MBSDocument: 0x7fd9dbb45f40> (entity: MBSDocument; id: 0x7fd9dbb3cd00 <x-coredata:///MBSDocument/tB55CB581-AEC0-4211-A78A-7C48377BACC2612> ; data:
...

我尝试了很多方法,其中包括在 observeValueForKeyPathfObject:change:context: 中删除对 super 的调用,或者在 init 中注册 等。但没有任何效果。好吧,我们将不胜感激。

提前致谢。

编辑:这是定义上下文的方式:

static void * KVODocumentIdContext = &KVODocumentIdContext;

编辑2:文档类继承自NSManagedObject



Best Answer-推荐答案


第一件事:我不会覆盖 initWithEntity:

这是苹果官方 NSManagedObject 类 API 文档的节选:

“您也不鼓励重写 initWithEntity:insertIntoManagedObjectContext: 或 dealloc。更改 initWithEntity:insertIntoManagedObjectContext: 方法中的值不会被上下文注意到,如果您不小心,这些更改可能不会被保存。大多数初始化应在其中一种唤醒…方法中执行自定义。”

因此,您可能应该在 awakeFromInsert: 或 awakeFromFetch: 中添加这些 KVO 观察结果然后在 didTurnIntoFault 中删除这些观察者)您的子类的重写方法,也许您可​​以免除添加和删除观察者的所有这些开销,具体取决于什么会影响您的计算属性。

如果影响计算属性的键路径不是很多关系,那么你不妨编写你的 documentID 计算属性 getter 访问器并实现类方法 +(NSSet *)keYPathsForValiesAffectingDocumentID,它返回一个包含键路径的 NSSet,如果更改将导致使用新值重新计算计算机属性。

关于ios - KVO 和 Core Data - 自观察托管对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30975997/






欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) Powered by Discuz! X3.4