2015-06-22 3 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: 
... 

Я пробовал много вещей, в том числе удаление вызова до super в observeValueForKeyPath:ofObject:change:context:, или регистрироваться в init и т. д. Но ничего не получилось. Ну, некоторая помощь будет принята с благодарностью.

Заранее спасибо.

Edit: Это как определяется контекст:

static void * KVODocumentIdContext = &KVODocumentIdContext; 

Edit 2: Класс документа наследует от NSManagedObject.

+0

Как вы использовали контекст для наблюдения. Похоже, что наблюдательный контекст как-то отличается. – Sandeep

+0

В соответствии с http://nshipster.com/key-value-observing/#correct-context-declarations я объявил контекст таким же образом (я отредактировал сообщение) – Zaphod

ответ

1

Первое первый: я бы не переопределить initWithEntity:

Это выдержка из официальной документации API от Apple для NSManagedObject класс:

«вы также обескуражен переопределение initWithEntity:. insertIntoManagedObjectContext :, или dealloc Изменение значений в initWithEntity: insertIntoManagedObjectContext: метод не будет замечен в контексте, и если вы не будете осторожны, эти изменения не могут быть сохранены Большинство начальных Настройка должна быть выполнена в одном из методов awake ....«

Таким образом, вы должны добавить эти наблюдения KVO в awakeFromInsert: или awakeFromFetch: (затем удалить эти наблюдатели в didTurnIntoFault) переопределенные методы вашего подкласса, возможно, вы избавитесь от всех этих накладных расходов, связанных с добавлением и удалением наблюдателей в зависимости от того, что влияет на ваше вычисленное свойство.

В случае, если ключевые пути, влияющие на вычисленное свойство, не связаны со многими отношениями, тогда вы можете просто написать свой идентификатор getput с идентификатором полученного документа documentID и реализовать метод класса + (NSSet *) keYPathsForValiesAffectingDocumentID который возвращает NSSet, содержащий ключи ключей, которые, если они будут изменены, приведут к перерасчету свойства компьютера с использованием новых значений.

0

KVODocumentIdContext является проблемной областью просьба уточнить, что и [супер наблюдать ..] метод

+0

Я отредактировал сообщение, чтобы объяснить, ve определил контекст. (Я использую это в соответствии с http://nshipster.com/key-value-observing/#correct-context-declarations) – Zaphod

+0

означает, что вы удалите контекст и проверьте, все ли в порядке? Также поделитесь классом rentarchy –

+0

Класс просто наследует от 'NSManagedObject', ничего не придумал здесь ... Но если я удалю контекст, как я узнаю, я не буду испортить встроенный KVO' NSManagedObject'? – Zaphod

Смежные вопросы