Ios KVO和核心数据-自观察托管对象
我认为这个问题很简单也很常见,但我仍然不明白为什么它不起作用。让我来说明一下背景: 假设我有一个很好的核心数据模型,其中有一个名为Document的实体。此文档包含类型、日期、编号和版本。。。例如,键入:D,日期:17-10-2015,编号:24和版本3。 此文档具有使用这四个值计算的和标识符:D20151017-24-R03 将会有很多这样的文档,我必须通过它的标识符来搜索它们,我还将使用大量的Ios KVO和核心数据-自观察托管对象,ios,core-data,ios8,nsmanagedobject,key-value-observing,Ios,Core Data,Ios8,Nsmanagedobject,Key Value Observing,我认为这个问题很简单也很常见,但我仍然不明白为什么它不起作用。让我来说明一下背景: 假设我有一个很好的核心数据模型,其中有一个名为Document的实体。此文档包含类型、日期、编号和版本。。。例如,键入:D,日期:17-10-2015,编号:24和版本3。 此文档具有使用这四个值计算的和标识符:D20151017-24-R03 将会有很多这样的文档,我必须通过它的标识符来搜索它们,我还将使用大量的nsfetchedresultscoontroller。所以暂时的可能性是正确的 这就是我所做的。观
nsfetchedresultscoontroller
。所以暂时的可能性是正确的
这就是我所做的。观察四个相关属性的第一个寄存器:
- (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];
}
}
就在这里,更新的文档ID
:
- (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:
...
编辑2:文档类继承自
NSManagedObject
kVodocumentContext是问题所在。请详细说明这一点和[super observe..]method第一件事:我不会用Entity重写initWithEntity:
这是NSManagedObject类苹果官方API文档的摘录:
还不鼓励您重写initWithEntity:insertIntoManagedObjectContext:,或dealloc。在initWithEntity:insertIntoManagedObjectContext:方法中更改值不会被上下文注意到,如果您不小心,这些更改可能不会被保存。大多数初始化自定义应在唤醒…方法之一中执行。“
因此,在给出了子类的awakeFromInsert:或awakeFromFetch:(然后在didturnintofult中删除这些观察器)重写方法之后,您可能应该在其中添加这些KVO观察值,也许您可以根据影响计算属性的因素,避免添加和删除观察器的所有开销
如果影响计算属性的键路径不是多对多的关系,那么您最好只编写documentID计算属性getter访问器并实现类方法+(NSSet*)KeyPathForvaliesFectingDocumentId,返回一个NSSet,其中包含如果更改将导致使用新值重新计算计算机属性的键路径。
[self addObserver:self
(如self.delegate=self
)你不需要观察自己的属性,你可以自定义设置
创建setter,调用dynamic super方法(由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
。您如何使用上下文进行观察。观察上下文似乎有所不同。根据我以相同的方式声明上下文(我编辑了文章),我编辑了文章,以解释我如何定义上下文。(我根据编辑)意思是在删除上下文并检查是否正常的同时?也共享类HirEarchy该类刚从NSManagedObject
继承,这里没有什么特别之处…但是如果我删除上下文,我怎么知道我不会弄乱NSManagedObject
的内置KVO?为什么调用[super observeValue..]是必需的吗?我不认为需要调用“super”,更仔细地使用上下文,或者删除它,你应该会没事的
@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