paulw11 / Seam3

Cloudkit based persistent store for Core Data
Other
209 stars 25 forks source link

SMStore.type is an "unsupported store type" #112

Open bcye opened 5 years ago

bcye commented 5 years ago

Hey,

I have tried (and failed to migrate my old store into the new Seam3 store using the tips in #59 and https://github.com/paulw11/migrateSample

Here is my code:

    func migrateToSeamStore() {

        // store references to URLs necessary for migration
        let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!
        let oldUrl = documentDirectory.appendingPathComponent("WHIR.sqlite")
        let newUrl = documentDirectory.appendingPathComponent("WHIR-Seam.sqlite")
        let modelUrl = Bundle.main.url(forResource: "WHIR", withExtension: "momd")

        if let managedObjectModel = NSManagedObjectModel(contentsOf: modelUrl!) {
            let container = NSPersistentContainer(name: "migrationContainer", managedObjectModel: managedObjectModel)
            let coordinator = container.persistentStoreCoordinator

            guard let _ = try? coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: oldUrl, options: nil), let oldStore = coordinator.persistentStore(for: oldUrl) else {
                fatalError("Failed to reference or create old store")
            }

            do {
                SMStore.registerStoreClass()
                SMStore.syncAutomatically = false
                try coordinator.migratePersistentStore(oldStore, to: newUrl, options:nil, withType:SMStore.type)
                verifyCloudKitAuth()
                self.smStore?.triggerSync()
                SMStore.syncAutomatically = true
            } catch {
                fatalError("Failed to migrate store: \(error)")
            }
        }

    }

    private lazy var persistentContainer: NSPersistentContainer = {

        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

        if let applicationDocumentsDirectory = urls.last {

            let url = applicationDocumentsDirectory.appendingPathComponent("WHIR-Seam.sqlite")
            let seamStoreExists = FileManager.default.fileExists(atPath: url.path)

            if !seamStoreExists {
                migrateToSeamStore()
            } else {
                let container = NSPersistentContainer(name: "WHIR-Seam")
                let coordinator = container.persistentStoreCoordinator

                let storeDescription = NSPersistentStoreDescription(url: url)
                storeDescription.type = SMStore.type
                container.persistentStoreDescriptions=[storeDescription]

                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.
                         */
                        fatalError("Unresolved error \(error), \(error.userInfo)")
                    }
                })
                return container
            }
        }

        fatalError("Unable to access documents directory")

    }()

    func verifyCloudKitAuth() {
        self.smStore?.verifyCloudKitConnectionAndUser() { (status, user, error) in
            guard status == .available, error == nil else {
                NSLog("Unable to verify CloudKit Connection \(error)")
                return
            }

            guard let currentUser = user else {
                NSLog("No current CloudKit user")
                return
            }

            var completeSync = false

            let previousUser = UserDefaults.standard.string(forKey: "CloudKitUser")
            if  previousUser != currentUser {
                do {
                    print("New user")
                    try self.smStore?.resetBackingStore()
                    completeSync = true
                } catch {
                    NSLog("Error resetting backing store - \(error.localizedDescription)")
                    return
                }
            }

            UserDefaults.standard.set(currentUser, forKey:"CloudKitUser")

            self.smStore?.triggerSync(complete: completeSync)
        }
    }

    init() {
        self.smStore = persistentContainer.persistentStoreCoordinator.persistentStores.first as? SMStore
    }
}

It fails and throws an SIGABRT because of an unsupported store type

Output:

2019-01-23 19:06:21.436784-0800 WHIR[76746:1270108] [AXMediaCommon] Unable to look up screen scale
2019-01-23 19:06:21.436977-0800 WHIR[76746:1270108] [AXMediaCommon] Unexpected physical screen orientation
2019-01-23 19:06:21.486231-0800 WHIR[76746:1270108] [AXMediaCommon] Unable to look up screen scale
2019-01-23 19:06:21.490758-0800 WHIR[76746:1270108] [AXMediaCommon] Unable to look up screen scale
2019-01-23 19:06:21.490855-0800 WHIR[76746:1270108] [AXMediaCommon] Unexpected physical screen orientation
2019-01-23 19:06:21.609579-0800 WHIR[76746:1270108] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported store type.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001082581bb __exceptionPreprocess + 331
    1   libobjc.A.dylib                     0x00000001077f6735 objc_exception_throw + 48
    2   CoreData                            0x0000000106d49800 __91-[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:]_block_invoke + 7136
    3   CoreData                            0x0000000106d59ea9 gutsOfBlockToNSPersistentStoreCoordinatorPerform + 201
    4   libdispatch.dylib                   0x000000010d967602 _dispatch_client_callout + 8
    5   libdispatch.dylib                   0x000000010d975653 _dispatch_lane_barrier_sync_invoke_and_complete + 132
    6   CoreData                            0x0000000106d44655 _perform + 213
    7   CoreData                            0x0000000106c27189 -[NSPersistentStoreCoordinator addPersistentStoreWithType:configuration:URL:options:error:] + 521
    8   CoreData                            0x0000000106d475ab -[NSPersistentStoreCoordinator _doAddPersistentStoreWithDescription:privateCopy:completionHandler:] + 379
    9   CoreData                            0x0000000106d47b1c -[NSPersistentStoreCoordinator addPersistentStoreWithDescription:completionHandler:] + 172
    10  CoreData                            0x0000000106cf5cbc -[NSPersistentContainer loadPersistentStoresWithCompletionHandler:] + 668
    11  WHIR                                0x0000000105f98ae7 $S4WHIR13CoreDataStackC19persistentContainer33_DF61067112A0FF1BBDDD35B28BAA9DAELLSo012NSPersistentF0CvgAGyXEfU_ + 1255
    12  WHIR                                0x0000000105f967ee $S4WHIR13CoreDataStackC19persistentContainer33_DF61067112A0FF1BBDDD35B28BAA9DAELLSo012NSPersistentF0Cvg + 302
    13  WHIR                                0x0000000105f978dd $S4WHIR13CoreDataStackCACycfc + 205
    14  WHIR                                0x0000000105f977b0 $S4WHIR13CoreDataStackCACycfC + 64
    15  WHIR                                0x0000000105f7ffe9 $S4WHIR19TableViewControllerC5coderACSgSo7NSCoderC_tcfc + 233
    16  WHIR                                0x0000000105f8016f $S4WHIR19TableViewControllerC5coderACSgSo7NSCoderC_tcfcTo + 47
    17  UIKitCore                           0x0000000109dac166 -[UIClassSwapper initWithCoder:] + 246
    18  UIFoundation                        0x00000001118f55ad UINibDecoderDecodeObjectForValue + 749
    19  UIFoundation                        0x00000001118f52b3 -[UINibDecoder decodeObjectForKey:] + 251
    20  UIKitCore                           0x0000000109db078e -[UIRuntimeConnection initWithCoder:] + 136
    21  UIFoundation                        0x00000001118f55ad UINibDecoderDecodeObjectForValue + 749
    22  UIFoundation                        0x00000001118f5854 UINibDecoderDecodeObjectForValue + 1428
    23  UIFoundation                        0x00000001118f52b3 -[UINibDecoder decodeObjectForKey:] + 251
    24  UIKitCore                           0x0000000109dae067 -[UINib instantiateWithOwner:options:] + 1220
    25  UIKitCore                           0x000000010a2e28b6 -[UIStoryboard instantiateViewControllerWithIdentifier:] + 181
    26  UIKitCore                           0x000000010a14103a -[UIApplication _loadMainStoryboardFileNamed:bundle:] + 112
    27  UIKitCore                           0x000000010a14150c -[UIApplication _loadMainInterfaceFile] + 272
    28  UIKitCore                           0x000000010a13fb25 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1357
    29  UIKitCore                           0x000000010995e4e9 __111-[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:]_block_invoke + 866
    30  UIKitCore                           0x000000010996729c +[_UICanvas _enqueuePostSettingUpdateTransactionBlock:] + 153
    31  UIKitCore                           0x000000010995e126 -[__UICanvasLifecycleMonitor_Compatability _scheduleFirstCommitForScene:transition:firstActivation:completion:] + 233
    32  UIKitCore                           0x000000010995eae0 -[__UICanvasLifecycleMonitor_Compatability activateEventsOnly:withContext:completion:] + 1085
    33  UIKitCore                           0x000000010995ccb5 __82-[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:]_block_invoke + 795
    34  UIKitCore                           0x000000010995c95f -[_UIApplicationCanvas _transitionLifecycleStateWithTransitionContext:completion:] + 435
    35  UIKitCore                           0x0000000109961a90 __125-[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:]_block_invoke + 584
    36  UIKitCore                           0x000000010996280e _performActionsWithDelayForTransitionContext + 100
    37  UIKitCore                           0x00000001099617ef -[_UICanvasLifecycleSettingsDiffAction performActionsForCanvas:withUpdatedScene:settingsDiff:fromSettings:transitionContext:] + 221
    38  UIKitCore                           0x000000010996693a -[_UICanvas scene:didUpdateWithDiff:transitionContext:completion:] + 392
    39  UIKitCore                           0x000000010a13e44e -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 515
    40  UIKitCore                           0x0000000109ce2d09 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 357
    41  FrontBoardServices                  0x00000001145752da -[FBSSceneImpl _didCreateWithTransitionContext:completion:] + 448
    42  FrontBoardServices                  0x0000000114580443 __56-[FBSWorkspace client:handleCreateScene:withCompletion:]_block_invoke_2 + 271
    43  FrontBoardServices                  0x000000011457fb3a __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 53
    44  libdispatch.dylib                   0x000000010d967602 _dispatch_client_callout + 8
    45  libdispatch.dylib                   0x000000010d96ab78 _dispatch_block_invoke_direct + 301
    46  FrontBoardServices                  0x00000001145b4ba8 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
    47  FrontBoardServices                  0x00000001145b4860 -[FBSSerialQueue _performNext] + 457
    48  FrontBoardServices                  0x00000001145b4e40 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
    49  CoreFoundation                      0x00000001081bd721 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    50  CoreFoundation                      0x00000001081bcf93 __CFRunLoopDoSources0 + 243
    51  CoreFoundation                      0x00000001081b763f __CFRunLoopRun + 1263
    52  CoreFoundation                      0x00000001081b6e11 CFRunLoopRunSpecific + 625
    53  GraphicsServices                    0x00000001115b91dd GSEventRunModal + 62
    54  UIKitCore                           0x000000010a14181d UIApplicationMain + 140
    55  WHIR                                0x0000000105f741f7 main + 71
    56  libdyld.dylib                       0x000000010d9dd575 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 
bcye commented 5 years ago

Ok so something weird is happening here, it seems like adding the storeDescription is causing the problem. It seems like SMStore.type is an unsupported type

let container = NSPersistentContainer(name: "WHIR")
                let coordinator = container.persistentStoreCoordinator

                let storeDescription = NSPersistentStoreDescription(url: url)
                storeDescription.type = SMStore.type
                container.persistentStoreDescriptions=[storeDescription]

                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.
                         */
                        fatalError("Unresolved error \(error), \(error.userInfo)")
                    }
                })
                return container
DARTHUHUS commented 5 years ago

Hey, You need to call "SMStore.registerStoreClass()" as early as possible. This should fix your issue.