使用EXC_BAD_ACCESS将NSSQLite迁移到Seam3存储类型失败

时间:2017-11-03 11:12:54

标签: ios swift core-data

我仍在尝试将现有的NSSQLiteStore正确迁移到SMStore.Type(Seam3)并遇到奇怪的问题。无法理解为什么会这样。我已经提出了the same for Paul on github,但可能有人会在我的代码中注意到原因并且能够提供帮助,而保罗很忙。

我有什么: 应用程序在iOS 10+上运行,NSSQLiteStore位于默认文件夹中。

测试步骤:

  1. 删除新商店(如果存在)及其位于新路径中的支持文件: 文件:///用户/ DJ-格洛克/库/开发商/ CoreSimulator /设备/ 3708F142-3BD0-4C70-8515-217B7785D285 /数据/集装箱/数据/应用/ 29B60BBC-0D17-4D6C-8107-0135C45B20BA /文档/ CafeManagerSeam3 .sqlite

  2. 运行应用。应用程序应检查是否存在新商店。如果不是 - 从默认迁移执行迁移。

  3. App尝试迁移存储并使用EXC_BAD_ACCESS失败。 但与此同时,我可以看到新商店出现在新路径中,如果我再次运行应用程序,它会使用新商店,没有明显的问题。

  4. enter image description here

    我的代码:

    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
        var window: UIWindow?
        var smStore: SMStore?
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
            if #available(iOS 10.0, *) {
            let storeDescriptionType = AppDelegate.persistentContainer.persistentStoreCoordinator.persistentStores.first?.type
                if storeDescriptionType == SMStore.type {
                    print("Store is SMStore")
                    print()
                    self.smStore = AppDelegate.persistentContainer.persistentStoreCoordinator.persistentStores.first as? SMStore
                }
            } else {
                let storeDescriptionType = AppDelegate.managedObjectContext.persistentStoreCoordinator?.persistentStores.first?.type
                if storeDescriptionType == SMStore.type {
                    print("Store is SMStore")
                    print()
                    self.smStore = AppDelegate.managedObjectContext.persistentStoreCoordinator?.persistentStores.first as? SMStore
                }
            }
    ...
        // MARK: - Core Data stack for iOS 10+
        @available(iOS 10.0, *)
        static var persistentContainer: NSPersistentContainer = {
            let container = NSPersistentContainer(name: "CafeManager")
            let persistentStoreCoordinator = container.persistentStoreCoordinator
    
            //MARK: Initializing Seam3
            SMStore.registerStoreClass()
            SMStore.syncAutomatically = true
    
            //MARK: Preparing URL
            let applicationDocumentsDirectory: URL = {
                let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
                return urls[urls.count-1]
            }()
            let newURL = applicationDocumentsDirectory.appendingPathComponent("CafeManagerSeam3.sqlite")
    
            //MARK: Check if SQLite store has been already migrated by checking if CafeManagerSeam3.sqlite exists.
            let seamStoreExists = FileManager.default.fileExists(atPath: newURL.path)
    
            if seamStoreExists {
                //If exists, then use it because it has been already migrated to Seam3 storage
                print("Already migrated, using \(newURL)")
    
                let storeDescription = NSPersistentStoreDescription(url: newURL)
                storeDescription.type = SMStore.type
                storeDescription.setOption("iCloud.iGlock.CafeManager.com" as NSString, forKey: SMStore.SMStoreContainerOption)
                storeDescription.setOption(NSNumber(value:SMSyncConflictResolutionPolicy.clientTellsWhichWins.rawValue), forKey:SMStore.SMStoreSyncConflictResolutionPolicyOption)
                container.persistentStoreDescriptions=[storeDescription]
    
                container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                    if let error = error as NSError? {
                        fatalError("Unresolved error \(error), \(error.userInfo)")
                    }
                })
                return container
    
            } else {
                //If does not exist, then migrate old storage to Seam3.
                print("Not yet migrated, migrating to \(newURL)")
    
                //Loadig default store
                container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                    if let error = error as NSError? {
                        fatalError("Failed to load default store \(error), \(error.userInfo)")
                    }
                })
                let defaultPersistentStore = container.persistentStoreCoordinator.persistentStores.last
                print("Default store is located here: \(defaultPersistentStore!.url!)")
    
                //Adding new Seam3 store
                do {
                    try persistentStoreCoordinator.addPersistentStore(ofType: SMStore.type, configurationName: nil, at: newURL, options: nil)
                    print("Seam store was added to the new url: \(newURL)")
                } catch {
                    fatalError("Failed to add new Seam store: \(error)")
                }
    
                //Migrating default store to new Seam store
                do {
                    try persistentStoreCoordinator.migratePersistentStore(defaultPersistentStore!, to: newURL, options: nil, withType:SMStore.type)
                    //Removing old store
                    if defaultPersistentStore != nil {
                        do {
                            try persistentStoreCoordinator.remove(defaultPersistentStore!)
                        } catch {
                            fatalError("Failed to remove default store \(error)")
                        }
                    }
                }
                catch {
                    fatalError("Failed to migrate to Seam store: \(error)")
                }
    
                //Setting additional parameters to Seam store to make it able to use CloudKit
                let storeDescription = NSPersistentStoreDescription(url: newURL)
                storeDescription.type = SMStore.type
                storeDescription.setOption("iCloud.iGlock.CafeManager.com" as NSString, forKey: SMStore.SMStoreContainerOption)
                storeDescription.setOption(NSNumber(value:SMSyncConflictResolutionPolicy.clientTellsWhichWins.rawValue), forKey:SMStore.SMStoreSyncConflictResolutionPolicyOption)
                container.persistentStoreDescriptions=[storeDescription]
    
                return container
            }
    

    输出:

    CoreData: annotation:  Failed to load optimized model at path '/Users/dj-glock/Library/Developer/CoreSimulator/Devices/3708F142-3BD0-4C70-8515-217B7785D285/data/Containers/Bundle/Application/3E4EB624-227E-4BD0-99F1-AA975D86BDA8/CafeManager.app/CafeManager.momd/CafeManager v2.omo'
    Not yet migrated, migrating to file:///Users/dj-glock/Library/Developer/CoreSimulator/Devices/3708F142-3BD0-4C70-8515-217B7785D285/data/Containers/Data/Application/100FB44C-C881-44C1-9D03-454FEBDB092B/Documents/CafeManagerSeam3.sqlite
    Default store is located here: file:///Users/dj-glock/Library/Developer/CoreSimulator/Devices/3708F142-3BD0-4C70-8515-217B7785D285/data/Containers/Data/Application/100FB44C-C881-44C1-9D03-454FEBDB092B/Library/Application%20Support/CafeManager.sqlite
    Seam store was added to the new url: file:///Users/dj-glock/Library/Developer/CoreSimulator/Devices/3708F142-3BD0-4C70-8515-217B7785D285/data/Containers/Data/Application/100FB44C-C881-44C1-9D03-454FEBDB092B/Documents/CafeManagerSeam3.sqlite
    2017-10-31 17:49:47.762 CafeManager[52561:7472303] Access to CloudKit has not been verified by calling verifyCloudKitConnection
    (lldb) po self
    error: Trying to put the stack in unreadable memory at: 0x7ffee595ef80.
    (lldb) 
    What am I doing wrong? Is it my misunderstanding of CoreData stack or something else?
    

    在崩溃后重新运行应用程序时的输出:

    objc[52621]: Class _NSZombie_OS_xpc_endpoint is implemented in both ?? (0x618000048340) and ?? (0x600000047290). One of the two will be used. Which one is undefined.
    CoreData: annotation:  Failed to load optimized model at path '/Users/dj-glock/Library/Developer/CoreSimulator/Devices/3708F142-3BD0-4C70-8515-217B7785D285/data/Containers/Bundle/Application/0B098A31-C927-44C0-87C2-2F2B944DF66C/CafeManager.app/CafeManager.momd/CafeManager v2.omo'
    Already migrated, using file:///Users/dj-glock/Library/Developer/CoreSimulator/Devices/3708F142-3BD0-4C70-8515-217B7785D285/data/Containers/Data/Application/932E6B3A-65B1-44F1-920B-DCE5F242C9C7/Documents/CafeManagerSeam3.sqlite
    Store is SMStore
    
    Sync Started
    No more records coming
    Sync Performed
    Sync performed successfully
    //some test insert that was loaded to Cloud.
    Sync Started
    No more records coming
    Sync Performed
    Sync performed successfully
    

1 个答案:

答案 0 :(得分:0)

错误已解决。使用了Paul的example

{
            // If does not exist, then migrate old storage to Seam3.
            print("Not yet migrated, migrating to \(newURL)")
            SMStore.syncAutomatically = false

            // Loadig default store
            container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                if let error = error as NSError? {
                    fatalError("Failed to load default store \(error), \(error.userInfo)")
                }
            })
            let defaultPersistentStore = container.persistentStoreCoordinator.persistentStores.last
            print("Default store is located here: \(defaultPersistentStore!.url!)")

            //Migrating default store to new Seam store
            do {
                try persistentStoreCoordinator.migratePersistentStore(defaultPersistentStore!, to: newURL, options: nil, withType:SMStore.type)
            }
            catch {
                fatalError("Failed to migrate to Seam store: \(error)")
            }

            //Setting additional parameters to Seam store to make it able to use CloudKit
            let storeDescription = NSPersistentStoreDescription(url: newURL)
            storeDescription.type = SMStore.type
            storeDescription.setOption("iCloud.iGlock.CafeManager.com" as NSString, forKey: SMStore.SMStoreContainerOption)
            storeDescription.setOption(NSNumber(value:SMSyncConflictResolutionPolicy.clientTellsWhichWins.rawValue), forKey:SMStore.SMStoreSyncConflictResolutionPolicyOption)
            container.persistentStoreDescriptions=[storeDescription]
            SMStore.syncAutomatically = true
            return container
        }