我认为这个问题很简单也很常见,但我仍然不明白为什么它不起作用。让我暴露上下文:
假设我有一个不错的核心数据模型,其中包含一个名为 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-推荐答案 strong>
第一件事:我不会覆盖 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/
|