0

我有以下任务组,使用 Swift 5.5 中的异步/等待并发,我在其中迭代米,onboardingMeter从核心数据中获取。这在 5 次中有 4 次都可以正常工作,但随后会导致 iOS 应用程序崩溃。我正在通过从 iOS 设备中删除应用程序来测试这一点,并从一开始就运行入职。有时我可以连续运行 4 次或 5 次或 6 次没有问题,然后它突然崩溃并出现以下错误:

2021-09-05 09:11:01.095537+0200 Curro[12328:1169419] [error] error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
CoreData: error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
2021-09-05 09:11:01.095954+0200 Curro[12328:1169419] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
*** First throw call stack:
(0x1857b105c 0x19dc63f64 0x1858ba538 0x1858c5df8 0x1857c68bc 0x18ce313d8 0x18cd13314 0x18cd140cc 0x105616700 0x105626a90 0x185769ce4 0x185723ebc 0x1857373c8 0x1a0edd38c 0x1880dae9c 0x187e58864 0x18d36da2c 0x18d29ab70 0x18d27bf2c 0x1048bba04 0x1048bbab0 0x10551da24)
libc++abi: terminating with uncaught exception of type NSException

这是失败的代码,let onboardingMeter = await OnboardingMeter.fromMeterDict永远不会返回,失败时我看不到第二个打印语句。

这是 Swift 测试版中的一个错误,还是我在这里犯了任何错误?当新的 iOS 15 测试版到来,以及 iOS 15 的正式版本发布时,我会再试一次。

await withTaskGroup(of: OnboardingMeter.self) { group in
    for (number, codableAddress) in meters {
        group.addTask {
            print("The following statement sometimes fails to return an onboarding meter, resulting in a crash")
            let onboardingMeter = await OnboardingMeter.fromMeterDict(number, address: codableAddress, in: moc)
            print("onboardingMeter:", onboardingMeter)
            return onboardingMeter
        }
    }
    for await meter in group {
        onboardingMeters.append(meter)
    }
}

OnboardingMeter.fromMeterDict功能:

extension OnboardingMeter {
    static func fromMeterDict(_ number: String, address: CodableAddress, in moc: NSManagedObjectContext) async -> OnboardingMeter {
        let me: OnboardingMeter = await moc.findOrCreateInstance(of: self, predicate: NSPredicate(format: "number == \(number)"))
        let address = await Address.createOrUpdate(from: address, in: moc)
        await moc.perform {
            me.address = address
            me.number = number
        }

        return me
    }
}

并找到OrCreateInstance:

    func findOrCreateInstance<T: NSManagedObject>(of type: T.Type, predicate: NSPredicate?) async -> T {
        if let found = await self.findFirstInstance(of: type, predicate: predicate) {
            return found
        } else {
            return T(context: self)
        }
    }
4

1 回答 1

0

尽管我需要查看更多代码来确认这一点,但我相信您正在返回一个已注册到托管对象上下文的托管对象。仅在perform调用结束时引用此类注册对象才有效。如果您需要在不同的执行上下文之间引用托管对象,请使用对象 ID 并根据需要重新获取,或者使用获取请求的字典表示选项:

let request: NSFetchRequest = ...
request.resultType = NSManagedObjectIDResultType // or NSDictionaryResultType
return request.execute()

我强烈建议您观看来自 WWDC 的视频。在 10 点 39 分,他们正在谈论这个问题。

于 2022-02-16T23:05:25.657 回答