为什么我使用NSManagedObject在自身上获得崩溃清除基于块的KVO?

我有一个具有复杂关系的Core Data模型,该模型已使用中间的“连接”对象(此问题的更多上下文:Maintaining Complex Unidirectional Relationships in Core Data)进行了建模。

我不希望使用该模型的代码了解中间连接对象,因此我向我的主要托管对象添加了一个数组属性,该属性公开了所连接的对象(我也希望可以观察到)。

@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

正如您从日志中看到的那样,在崩溃声称是问题之前,我正在使观察无效。如果我尝试将观察值设置为nilwillTurnToFault()中,我的应用此时崩溃了。

我是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()会发生什么。

我正在Xcode 11.1中使用Swift 5构建OSX 10.12。

编辑3:

转载于一个新的简单项目:https://github.com/GilesHammond/KVO-Core-Data-Crash

zjc121 回答:为什么我使用NSManagedObject在自身上获得崩溃清除基于块的KVO?

关键问题似乎是我的核心数据模型在模块中。

我已经更新了示例项目,以在此处显示潜在的错误。

我已经与Apple进行了交谈。似乎存在系统错误。在模块中,Swift当前无法正确清除NSManagedObject上的NSKeyValueObservation。

我已通过反馈助手向Apple提交了一个问题。

本文链接:https://www.f2er.com/3166778.html

大家都在问