我认为这个问题非常简单和常见,但我仍然不明白为什么它不起作用。让我揭露背景:
让我说我有一个很好的核心数据模型,其中有一个名为Document的实体。此文档包含类型,日期,编号和版本...例如,类型: D ,日期: 17-10-2015 ,编号: 24 和版本 3 。 本文档使用以下四个值计算和标识符: D20151017-24-R03 。
会有很多这些文档,我将不得不通过其标识符进行搜索,我也会使用很多NSFetchedResultsController
。所以瞬间的可能性就是出来了。
这就是我所做的。首先注册观察四个相关属性:
- (instancetype)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)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) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == KVODocumentIdContext) {
[self updateDocumentId];
}
else {
[super observeValueForKeyPath:keyPath ofObject:object 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 isEqualToNumber:@0]?@"":[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 -observeValueForKeyPath:ofObject: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:
...
我尝试过很多事情,其中包括取消super
中observeValueForKeyPath:ofObject:change:context:
的电话,或init
中的注册等。但没有任何效果。好吧,非常感谢一些帮助。
提前致谢。
编辑:这是定义上下文的方式:
static void * KVODocumentIdContext = &KVODocumentIdContext;
编辑2 :文档类继承自NSManagedObject
。
答案 0 :(得分:1)
首先要做的是:我不会覆盖initWithEntity:
这是Apple针对NSManagedObject类的官方API文档的摘录:
“您也不鼓励覆盖initWithEntity:insertIntoManagedObjectContext:或dealloc。更改initWithEntity:insertIntoManagedObjectContext:方法中的值将不会被上下文注意到,如果您不小心,可能无法保存这些更改。应该在一个清醒......方法中执行自定义。“
所以在给你的时候,你应该在awakeFromInsert:或awakeFromFetch :(然后在didTurnIntoFault中删除这些观察者)覆盖你的子类的方法中添加这些KVO观察,也许你可以免除所有这些增加和删除观察者的开销,这取决于什么会影响你的计算属性。
如果影响计算属性的keypath不是很多关系,那么你也可以编写你的documentID计算属性getter访问器并实现类方法+(NSSet *)keYPathsForValiesAffectingDocumentID,它返回一个包含keypath的NSSet。更改将导致使用新值重新计算计算机属性。
答案 1 :(得分:0)
KVODocumentIdContext是问题区域请详细说明和[超级观察..]方法
答案 2 :(得分:0)
[self addObserver:self
(如self.delegate = self
)应该关闭了闹钟!您无需观察自己的属性,即可创建自定义设置器。
创建设置器,调用动态超级方法(由NSManagedObject
自动添加 ),然后您自定义工作,例如
@interface Event (DynamicAccessors)
- (void)managedObjectOriginal_setTimestamp:(NSDate *)timestamp;
@end
@implementation Event
- (void)setTimestamp:(NSDate *)timestamp{
[self managedObjectOriginal_setTimestamp:timestamp];
// custom action for when the timestamp has been changed.
}
@end
因此,您将创建4个自定义设置器,并从所有设置中调用updateDocumentId
。