KVO не работает для пользовательского свойства NSManagedObject - PullRequest
0 голосов
/ 04 октября 2018

У меня есть подкласс NSManagedObject Folder с состоянием Availability

@objc enum Availability: Int16 {
  case unknown
  case available
  case unavailable
}

Папка должна делать дополнительные вещи (например, удалять связанные файлы) всякий раз, когда изменяется ее доступность.Таким образом,

  1. internalAvailability сохранено в основных данных
  2. Вычисляемое свойство availability, используя указанное выше свойство

`

extension Folder {
  @NSManaged private var internalAvailability: Availability
}

extension Folder {
  private func deleteFiles(...) {
  ...
  }

  @objc dynamic public var availability: Availability {
    get {
      return internalAvailability
    }
    set {
      willChangeValue(forKey: "availability")
      deleteFiles()
      internalAvailability = newValue
      didChangeValue(forKey: "availability")
    }
  }
}

Используя Reactive, я хочу изменить заголовок элемента навигации в зависимости от доступности, но сигнал никогда не вызывается один раз!

`` `

let property = DynamicProperty<NSNumber>(object: folder, keyPath: "availability")
internalVariable = property // To have a reference of property

navigationItem.reactive.title <~ property.map { (stateNumber) -> String in
  guard let a = Availability(rawValue: stateNumber.int16Value) else {
      assertionFailure()
      return ""
  }
  let prefix = a == .available ? "" : "(Nope) "
  return "\(prefix)\(folder.name)"
}

Я явно добавил соответствие KVO ксвойство в надежде, что это начнет работать, но, увы, безрезультатно.

Редактировать: если я создаю DynamicProperty на internalAvailability вместо availability, все работает плавно ..

1 Ответ

0 голосов
/ 05 октября 2018

Добавление в качестве ответа, поскольку оно стало учебным упражнением.Надеюсь, кому-то еще это будет полезно.

Приложение использует архитектуру множественного управляемогоObjectContext (moc).1 приватный moc для внесения изменений и 1 moc основного потока, который синхронизируется с помощью mergeChanges .

. В приведенном выше коде navigationItem использует экземпляр папки, хранящийся в main-moc.DynamicProperty прослушивает изменения KVO в экземпляре папки этого основного moc.Давайте назовем эту главную папку.Когда я делаю изменения, я изменяю экземпляр папки, которую мы имеем на private-moc.Давайте назовем это private-folder.

При изменении private-folder и вызове save на private-moc, передается уведомление с именем NSManagedObjectContextDidSave.main-moc синхронизирует себя с помощью mergeChanges.

mergeChanges изменяет основную папку, но обратите внимание, что она никогда не вызовет computed-property-setter availability.Он напрямую меняет internalAvailability.

. Таким образом, уведомления KVO о нашем вычисленном свойстве не публикуются.

TL; DR При выполнении KVO для NSManagedObjectподкласс, используйте сохраненное свойство вместо вычисленного.Если у вас есть сценарий multi-moc (контекст управляемого объекта) и вы используете mergeChanges для синхронизации, метод setter для вашего вычисленного свойства не вызывается при синхронизации.

Edit (Solution): добавить метод шаблона keyPathsForValuesAffecting<KeyName> КВО соответствующую документацию

@objc class func keyPathsForValuesAffectingAvailability() -> Set<NSObject> {
  return [#keyPath(Folder.internalAvailability) as NSObject]
}
...