baymak
baymak

Reputation: 109

Apple rejects my app due to crash in CoreData integration file but can't reproduce

I developed an app using CoreData and CloudKit. It gives some warning message in the console but works with no problem. However Apple rejected due to crash which I could not replicate. Really appreciate if you could advise how to address the issue.I implemented CoreData and CloudKit based on this material:

CoreDataImplementation

This is crash log from Apple:

enter image description here

In the splash screen CoreDataStack file is called:

struct SplashView: View {
    
    @EnvironmentObject var iconSettings: IconNames
    let persistenceController = CoreDataStack.shared
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    @AppStorage("isOnboarding") var isOnboarding: Bool = true
    @StateObject private var modelData = ExLibrisModelData()
    
    @State var isActive: Bool = false
    
    var body: some View {
        ZStack {
            if self.isActive {
                ContentView()
                    .environmentObject(modelData)
                    .environmentObject(IconNames())
                    .environment(\.managedObjectContext, CoreDataStack.shared.context)
                    .environment(\.urlImageOptions, URLImageOptions(
                        maxPixelSize: CGSize(width: 600.0, height: 600.

And here is my CoreDataStack file where I get the crash according to the report.

final class CoreDataStack: ObservableObject {
    static let shared = CoreDataStack()
    
    var context: NSManagedObjectContext {
        persistentContainer.viewContext
    }
    
    static let appGroupName = "group.com.Bookshelf"
    
    static let containerURL: URL = {
        FileManager.default.containerURL(
            forSecurityApplicationGroupIdentifier: CoreDataStack.appGroupName)!
    }()
    
    var ckContainer: CKContainer {
        let storeDescription = persistentContainer.persistentStoreDescriptions.first
        
        
        guard let identifier = storeDescription?.cloudKitContainerOptions?.containerIdentifier else {
            fatalError("Unable to get container identifier")
        }
        return CKContainer(identifier: identifier)
    }
    

    var privatePersistentStore: NSPersistentStore {
        guard let privateStore = _privatePersistentStore else {
            fatalError("Private store is not set")
        }
        return privateStore
    }
    
    var sharedPersistentStore: NSPersistentStore {
        guard let sharedStore = _sharedPersistentStore else {
            fatalError("Shared store is not set")
        }
        return sharedStore
    }
    
    
    lazy var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "Bookshelf")
        
        guard let privateStoreDescription = container.persistentStoreDescriptions.first else {
            fatalError("Unable to get persistentStoreDescription")
        }
        
        let storesURL = privateStoreDescription.url?.deletingLastPathComponent()
        privateStoreDescription.url = storesURL?.appendingPathComponent("private.sqlite")
        let sharedStoreURL = storesURL?.appendingPathComponent("shared.sqlite")
        
        guard let sharedStoreDescription = privateStoreDescription.copy() as? NSPersistentStoreDescription else {
            fatalError("Copying the private store description returned an unexpected value.")
        }
        sharedStoreDescription.url = sharedStoreURL
        
        guard let containerIdentifier = privateStoreDescription.cloudKitContainerOptions?.containerIdentifier else {
            fatalError("Unable to get containerIdentifier")
        }
        
        let sharedStoreOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
        sharedStoreOptions.databaseScope = .shared
        sharedStoreDescription.cloudKitContainerOptions = sharedStoreOptions
        container.persistentStoreDescriptions.append(sharedStoreDescription)
        
        container.loadPersistentStores { loadedStoreDescription, error in
            if let error = error as NSError? {
                fatalError("Failed to load persistent stores: \(error)")
            } else if let cloudKitContainerOptions = loadedStoreDescription.cloudKitContainerOptions {
                guard let loadedStoreDescriptionURL = loadedStoreDescription.url else {
                    return
                }
                
                if cloudKitContainerOptions.databaseScope == .private {
                    let privateStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescriptionURL)
                    self._privatePersistentStore = privateStore
                } else if cloudKitContainerOptions.databaseScope == .shared {
                    let sharedStore = container.persistentStoreCoordinator.persistentStore(for: loadedStoreDescriptionURL)
                    self._sharedPersistentStore = sharedStore
                }
            }
        }
        
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        container.viewContext.automaticallyMergesChangesFromParent = true
        do {
            try container.viewContext.setQueryGenerationFrom(.current)
        } catch {
            fatalError("Failed to pin viewContext to the current generation: \(error)")
        }
           
        return container
    }()
    
    private var _privatePersistentStore: NSPersistentStore?
    private var _sharedPersistentStore: NSPersistentStore?
    private init() {}
}

The console warnings are below. I have several of those:

CoreData: warning: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1093): <NSCloudKitMirroringDelegate: 0x282340540>: Successfully set up CloudKit integration for store (0811C705-3EB2-4C73-BC5B-B96B43E4F2E0): <NSSQLCore: 0x106c15b40> (URL: file:///var/mobile/Containers/Data/Application/CAA6F402-F5D0-496E-8E32-01299A0B7C7E/Library/Application%20Support/private.sqlite)

CoreData: warning: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1093): <NSCloudKitMirroringDelegate: 0x2823407e0>: Successfully set up CloudKit integration for store (1F2E3F9B-9DD9-4D61-9DB9-ADD2A3DE9D8D): <NSSQLCore: 0x106c087d0> (URL: file:///var/mobile/Containers/Data/Application/CAA6F402-F5D0-496E-8E32-01299A0B7C7E/Library/Application%20Support/shared.sqlite)

CoreData: warning: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _enqueueRequest:]_block_invoke_2(990): Failed to enqueue request: <NSCloudKitMirroringExportRequest: 0x28397cdc0> 709BC9FC-3172-4F7C-9878-A5E3412E8425

CoreData: warning: CoreData+CloudKit: -NSCloudKitMirroringDelegate finishedAutomatedRequestWithResult:: Finished request '<NSCloudKitMirroringExportRequest: 0x28397cdc0> 709BC9FC-3172-4F7C-9878-A5E3412E8425' with result: <NSCloudKitMirroringResult: 0x2814eb090> storeIdentifier: 0811C705-3EB2-4C73-BC5B-B96B43E4F2E0 success: 0 madeChanges: 0 error: Error Domain=NSCocoaErrorDomain Code=134417 "Request '<NSCloudKitMirroringExportRequest: 0x28397cdc0> 709BC9FC-3172-4F7C-9878-A5E3412E8425' was cancelled because there is already a pending request of type 'NSCloudKitMirroringExportRequest'." UserInfo={NSLocalizedFailureReason=Request '<NSCloudKitMirroringExportRequest: 0x28397cdc0> 709BC9FC-3172-4F7C-9878-A5E3412E8425' was cancelled because there is already a pending request of type 'NSCloudKitMirroringExportRequest'.}

Upvotes: 0

Views: 260

Answers (1)

malhal
malhal

Reputation: 30811

It's probably caused by the lazy var persistentContainer. Or it's caused by let persistenceController = CoreDataStack.shared and .environment(\.managedObjectContext, CoreDataStack.shared.context) where as it should be .environment(\.managedObjectContext, persistenceController.viewContext)

But try changing CoreDataStack to a struct to match what is in Xcode's template since that is the tried and tested way to integrate Core Data with SwiftUI and using Combine's ObservableObject class is non-standard.

You'll also need to fix this: .environmentObject(IconNames()) You can't init objects in body like that.

Upvotes: -1

Related Questions