2015-06-22 85 views
2

我認爲這個問題很簡單和常見,但我仍然不明白爲什麼它不起作用。讓我公開一下上下文:KVO和核心數據 - 自我觀察管理對象

比方說,我有一個很好的核心數據模型和一個名爲Document的實體。這份文件有一個類型,日期,編號和版本...例如,類型:d,日期:17-10-2015,編號:和版本。 本文檔具有以下四個值計算的標識符: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][email protected]"":[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: 
... 

我試過很多東西,其中包括刪除通話到superobserveValueForKeyPath:ofObject:change:context:,或登記在init等,但沒有奏效。那麼,一些幫助將不勝感激。

在此先感謝。

編輯:這是上下文是如何定義的:

static void * KVODocumentIdContext = &KVODocumentIdContext; 

編輯2:文檔類從NSManagedObject繼承。

+0

您是如何使用上下文進行觀察的。看起來上下文似乎有所不同。 – Sandeep

+0

根據http://nshipster.com/key-value-observing/#correct-context-declarations我以同樣的方式宣佈上下文(我已編輯帖子) – Zaphod

回答

1

第一件事,第一:我不會覆蓋initWithEntity:

這是蘋果的官方NSManagedObject API文檔的摘錄類:

「你也不希望重寫initWithEntity:insertIntoManagedObjectContext:或dealloc。改變initWithEntity:insertIntoManagedObjectContext:方法中的值不會被上下文注意到,如果你不小心,那些改變可能不會被保存。最初定製應該在清醒的方法之一中執行。「

所以有給你應該在任何awakeFromInsert可能添加這些志願意見:(在didTurnIntoFault然後刪除這些觀察員)覆蓋方法,你的子類的,或許你可以從所有這方面的開銷添加和刪除觀察員就饒了自己:或awakeFromFetch取決於影響你計算屬性的因素

如果影響計算屬性的關鍵路徑不是很多關係,那麼你可能只需編寫你的documentID計算屬性getter訪問器並實現類方法+(NSSet *)keYPathsForValiesAffectingDocumentID它返回一個包含關鍵路徑的NSSet,如果這個關鍵路徑改變了,將導致計算機屬性使用新值重新計算。

0

KVODocumentIdContext的問題區域,請詳細說明這一點,[超級觀察..]法

+0

我編輯了這篇文章,解釋我如何「已經定義了上下文。 (我按照http://nshipster.com/key-value-observing/#correct-context-declarations) – Zaphod

+0

的意思是,除去上下文並檢查是否正常?也分享類僱傭主義 –

+0

該類只是從NSManagedObject繼承,這裏沒有什麼特別的......但是如果我刪除上下文,我將如何知道我不會搞亂NSManagedObject的內建KVO? – Zaphod