Как сделать идеальный KVO для NSManagedObject?

Perfect KVO здесь состоит из двух частей: правильно добавить наблюдателя и правильно удалить наблюдатель.

История:

  1. Я использую одну UITableViewCell (ячейку) для отображения одного NSManagedObject (объекта).
  2. Каждый объект имеет некоторые динамические свойства, которые необходимо отслеживать его ячейкой.
  3. Не все объекты имеют одинаковый набор наблюдаемых свойств. Я добавляю наблюдателей ключевого пути выборочно следующим образом:

    if (object.thumbnail_pic_url) [объект addObserver: ячейка forKeyPath: @ параметры «thumbnail_picture»: 0 context: NULL];

  4. Объект может быть удален. Я должен удалить наблюдателей при удалении объекта. База данных очень большая и сложная, поэтому я определенно не хочу регистрировать все ячейки для получения moc-уведомлений, таких как NSManagedObjectContextObjectsDidChangeNotification. Но я могу согласиться на добавление ivar ячейки в объект, если мне нужно, даже если это опять же хороший шаблон проектирования Modle-View-Controller.

Проблема: как правильно удалить наблюдателя (ячейку) для всех зарегистрированных путей ключа из объекта, когда он удален?

По сути, это большая проблема, которую можно разделить на две небольшие проблемы:

  1. Где лучше всего разместить код удаления наблюдателя?
  2. Как определить, какие ключевые пути нужно отменить? Я не могу запросить его свойства после удаления объекта - это вызовет невыполнимые сбои, поэтому я не могу писать такой код:

    if (object.thumbnail_pic_url) [объект removeObserver: ячейка forKeyPath: @ "thumbnail_picture"];

и я не могу слепо удалить наблюдателя для незарегистрированного ключевого пути - будут выброшены исключения (Невозможно удалить наблюдателя для ключевого пути "thumbnail_picture", потому что он не зарегистрирован как наблюдатель.).


person an0    schedule 29.09.2011    source источник
comment
Как предложение, пробовали ли вы использовать fetchedResultsController для управления обновлениями tableview?   -  person Rog    schedule 30.09.2011
comment
Спасибо @Rog. Конечно, я им пользуюсь. Вы имеете в виду отмену регистрации KVO в методах NSFetchedResultsControllerDelegate? Это возможный способ. Но когда я получаю вызов делегата, объект уже удален, не так ли? Тогда это не поможет в решении проблемы с указанием путей для отмены регистрации.   -  person an0    schedule 30.09.2011


Ответы (3)


an0,

Существует метод NSManagedObject только для выполнения функций удаления по времени: -prepareForDeletion.

В его документации утверждается: «Вы можете реализовать этот метод для выполнения любых операций, необходимых перед удалением объекта, таких как настраиваемое распространение до разрыва отношений или реконфигурация объектов с использованием наблюдения за ключом».

Вы также можете использовать: -willTurnIntoFault и -didTurnIntoFault. Но я думаю, вам будет приятнее использовать -prepareForDeletion.

Андрей

P.S. Этот метод задокументирован в справочнике по классам. Я со всем уважением предлагаю вам сэкономить время, прочитав документацию.

person adonoho    schedule 01.10.2011
comment
@Andrew, спасибо, -prepareForDeletion - это то, что я понял и использовал. Но мне все равно нужно уведомить ячейку о смерти объекта, чтобы она отменила регистрацию KVO. Хоть и некрасиво, но работает :) - person an0; 02.10.2011

Основная проблема реализации KVO здесь заключается в том, что вы не знаете, когда объект удаляется, по крайней мере, не за пределами подкласса NSManagedObject. Что вы действительно могли бы сделать, так это создать общий делегат в подклассе NSManagedObject и переопределить его метод didChangeValueForKey:

  // DataObservingManagedObject.h

  #import <Foundation/Foundation.h>
  #import <MMRecord/MMRecord.h>

  @protocol DataObservingDelegate <NSObject>

  -(void)valueChangedForKey:(NSString*)key andValue:(id)value;
  @end

  @interface DataObservingManagedObject : NSManagedObject

  @property(nonatomic,weak)id<UserStatusDelegate> changeDelegate;

  @end

  //DateObservingManagedObject.m

  #import "DateObservingManagedObject.h"

  @implementation DateObservingManagedObject

  @synthesize changeDelegate=_changeDelegate;


  -(void)didChangeValueForKey:(NSString *)key{
    [self.changeDelegate valueChangedForKey:key andValue:[self valueForKey:key]];
  }

  @end
person Tapan Thaker    schedule 03.04.2014
comment
будьте осторожны, в документации Apple говорится, что нельзя отменять ‹br/› -(void)didChangeValueForKey - person GOrozco58; 29.02.2016

Я считаю, что ошибка в шаге 1. Ячейки должны быть предназначены для отображения различных объектов. Ячейки - это просто представления с метками, которые могут отображать все, что угодно. Таблицы оптимизированы для повторного использования одних и тех же ячеек для разных объектов данных. В вашем VC создайте методы configureCellWithEvent, configureCellWithVenue и т. Д., Затем вы можете удалить из очереди ячейку с общим идентификатором и передать ее этим методам. Тогда у вас, скорее всего, даже не будет вопроса о том, когда добавлять наблюдателей удаления, потому что в ячейках не должно быть наблюдателей за объектами.

person malhal    schedule 28.01.2019