少数用户核心数据迁移过程卡住

问题描述 投票:0回答:0

摘要

我遇到了一个问题,在更新应用程序后,Core Data 迁移过程对少数用户卡住了。

环境

我正在使用 SwiftUI + Core Data,目标是 iOS 15.0+。

说明

我不确定原因,无法在本地重现。

对模型的相应修改是为两个实体添加一个非可选的Int64字段,其他没有变化。用户的崩溃日志对应于

container.loadPersistentStores(completionHandler: { (storeDescription, error) in,
行所以我假设错误发生在迁移过程中。

我尝试过的

我曾多次尝试在本地环境中重现崩溃,但都失败了。我的环境中的迁移过程对我来说似乎很好。

已排除的可能性有:

  1. 主app和widget同时迁移导致的失败。如果迁移仍在进行中,我添加了一个逻辑来延迟小部件迁移,但崩溃仍然存在。而一些不使用小部件的用户仍然会遇到这个问题。
  2. 存储空间不足。一些用户有超过200G的可用空间,但仍然遇到这个问题。

我已经为新的非可选 Int64 设置了默认值,这里是模型更改的相关 git diff。加粗的“订单”字段是我添加的新字段。

相关代码

    <entity name="Preset" representedClassName="Preset" syncable="YES">
        <attribute name="createTime" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
        <attribute name="detail" optional="YES" attributeType="String"/>
        **<attribute name="order" attributeType="Integer 64" minValueString="0" defaultValueString="0" usesScalarValueType="YES"/>**
        <relationship name="belongsTo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Project" inverseName="presets" inverseEntity="Project"/>
        <relationship name="tagBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Tag" inverseName="presets" inverseEntity="Tag"/>
    </entity>
...
        <attribute name="id_" optional="YES" attributeType="String"/>
        <attribute name="isArchived" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
        <attribute name="name" optional="YES" attributeType="String"/>
        **<attribute name="order" attributeType="Integer 64" minValueString="0" defaultValueString="0" usesScalarValueType="YES"/>**
        <relationship name="entries" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TimeEntry" inverseName="belongsTo" inverseEntity="TimeEntry"/>
        <relationship name="presets" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Preset" inverseName="belongsTo" inverseEntity="Preset"/>
...

这里是我的 Persistence.swift 容器初始化代码:

init(inMemory: Bool = false) {
    container = NSPersistentCloudKitContainer(name: "Project")
    guard let groupContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.Project") else {
        logger.critical("Persistant init failed to get groupContainerURL")
        preconditionFailure("Persistant init failed to get groupContainerURL")
    }
    let storeURL = groupContainerURL.appendingPathComponent("Project.sqlite")
    if inMemory {
        container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
    } else {
        container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeURL)]
    }
    
    if container.isNeedMigration(url: storeURL) {
        logger.notice("Core Data model need Migration")
        #if APP_WIDGET
        for idx in 0..<3 {
            logger.notice("Widget sleeping \(idx+1).")
            sleep(3)
            if !container.isNeedMigration(url: storeURL) {
                break
            }
        }
        #endif
    }
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            
            /*
             Typical reasons for an error here include:
             * The parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            logger.critical("Unresolved error \(error.localizedDescription, privacy: .public), \(error.userInfo, privacy: .public), error: \(error)")
            fatalError("Unresolved error \(error.localizedDescription), \(error.userInfo)")
        }
    })
    container.viewContext.automaticallyMergesChangesFromParent = true
}

所以我想找出崩溃的原因并修复它,请给我一些建议,谢谢。

崩溃信息

swift swiftui core-data core-data-migration
© www.soinside.com 2019 - 2024. All rights reserved.