У меня есть модель базовых данных со сложными отношениями, которые я смоделировал с промежуточными объектами «Соединение» (дальнейший контекст в этом вопросе: Ведение сложных однонаправленных отношений в базовых данных ).
Я не хочу, чтобы код, использующий модель, знал о промежуточных объектах соединения, поэтому я добавляю свойство массива к моим основным управляемым объектам, которое предоставляет доступ к объектам, к которым они подключены (которые я тоже хочу наблюдать).
@objc dynamic public internal(set) lazy var hosts: [Point] = {
let initialHosts = hostConnections.map { $0.superpoint }
hostsObservation = track(\Matter.hostConnections_!, on: self,
mapping: \HostConnection.superpoint, to: #keyPath(hosts))
return initialHosts
}()
Приведенный выше код устанавливает наблюдение за NSOrderedSet
соединений при инициализации массива hosts
(используя универсальную функцию, которая может создать этот шаблон для всех моих типов соединений). Наблюдения запускаются, как и ожидалось.
Я лишил законной силы наблюдение в willTurnIntoFault()
:
override public func willTurnIntoFault() {
hostsObservation?.invalidate()
print("hostsObservation \(hostsObservation) invalidated")
super.willTurnIntoFault()
}
Однако я получаю сбой, когда этот объект освобожден в NSKVODeallocate
.
hostsObservation Optional(<_NSKeyValueObservation: 0x600000ccd920>) invalidated
2019-11-04 12:02:06.467620+0000 Frame[27900:5614740] [General] An instance 0x60000300bc30 of class FrameGraph.Subject_Subject_ was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x6000002d6ae0> (
<NSKeyValueObservance 0x600000ccd950: Observer: 0x600000ccd920, Key path: hostConnections_, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x600000c78b10>
...
0 CoreFoundation 0x00007fff3f590e45 __exceptionPreprocess + 256
1 libobjc.A.dylib 0x00007fff6a1e63c6 objc_exception_throw + 48
2 CoreFoundation 0x00007fff3f590c77 +[NSException raise:format:] + 193
3 Foundation 0x00007fff4180f349 NSKVODeallocate + 442
4 CoreData 0x00007fff3f060772 -[_PFManagedObjectReferenceQueue _processReferenceQueue:] + 1154
Как вы можете видеть из журнала, я лишил законной силы наблюдение непосредственно перед аварией, утверждая, что это проблема. Если я попытаюсь установить для наблюдения значение nil
в willTurnToFault()
, мое приложение в этот момент вылетает.
Я новичок в Core Data, может кто-нибудь помочь мне с тем, чего мне здесь не хватает? Почему объект, который наблюдает за тем, как происходит сбой его собственного свойства?
РЕДАКТИРОВАТЬ 1:
Моя функция отслеживания выглядит следующим образом:
internal func track<P: Point, C: Connection>(_ trackedPath: KeyPath<P, NSOrderedSet>,
on point: P,
mapping connectionPath: KeyPath<C, Point>,
to mappedPoints: String)
-> NSKeyValueObservation
{
return point.observe(trackedPath) { [unowned point] data, change in
// ...
}
}
РЕДАКТИРОВАНИЕ 2:
Я сократил код сбоя до этого:
public class Matter: Point
{
override public func awakeFromFetch() {
super.awakeFromFetch()
print("\(hosts)") // Initialise lazy member and set observation
}
public override func willTurnIntoFault() {
super.willTurnIntoFault()
hostsObservation = nil // <-- EXC_BAD_ACCESS
}
@objc dynamic public internal(set) lazy var hosts: [Point] = {
hostsObservation = observe(\.hostConnections_) { [unowned self] data, change in } // Empty observation closure
return []
}()
private var hostsObservation: NSKeyValueObservation?
}
// Matter+CoreDataProperties.swift - auto generated
extension Matter {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Matter> {
return NSFetchRequest<Matter>(entityName: "Matter")
}
@NSManaged public var hostConnections_: NSOrderedSet?
}
Я не понимаю, что происходит с hostsObservation
, чтобы установить его на nil
в willTurnToFault()
сбой.
Я строю для OSX 10.12, используя Swift 5 в Xcode 11.1.
РЕДАКТИРОВАТЬ 3:
Воспроизведено в новом простом проекте: https://github.com/GilesHammond/KVO-Core-Data-Crash