Since my last question (here toggle between local and iCloud CoreData store) I was able to make a lot of progress.
I am switching between NSPersistentCloudKitContainer
and NSPersistenttContainer
But...
When I switch off the CloudKit synchronization and update the container, the sync is still active.
After restarting the app manually the sync is deactivated.
This is the same problem some people are describing in the comments here...
CoreData+CloudKit | On/off iCloud sync toggle
But I wasn't able to find a solution.
MyApp.swift
@main
struct MyApp: App {
@StateObject private var persistenceContainer = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(CoreBluetoothViewModel())
.environment(\.managedObjectContext, persistenceContainer.container.viewContext)
}
}
}
PersistenceController
import CoreData
class PersistenceController: ObservableObject{
static let shared = PersistenceController()
lazy var container: NSPersistentContainer = {
setupContainer()
}()
init() {
container = setupContainer()
}
func updateContainer() {
saveContext()
container = setupContainer()
saveContext()
}
private func setupContainer() -> NSPersistentContainer {
let iCloud = UserDefaults.standard.bool(forKey: "iCloud")
do {
let newContainer = try PersistentContainer.getContainer(iCloud: iCloud)
guard let description = newContainer.persistentStoreDescriptions.first else { fatalError("No description found") }
if iCloud {
newContainer.viewContext.automaticallyMergesChangesFromParent = true
newContainer.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
} else {
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.cloudKitContainerOptions = nil
}
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
newContainer.loadPersistentStores { (storeDescription, error) in
if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") }
}
return newContainer
} catch {
print(error)
}
fatalError("Could not setup Container")
}
private func saveContext() {
do {
try container.viewContext.save()
} catch {
let error = error as NSError
fatalError("ERROR: \(error)")
}
}
}
final class PersistentContainer {
private static var _model: NSManagedObjectModel?
private static func model(name: String) throws -> NSManagedObjectModel {
if _model == nil {
_model = try loadModel(name: name, bundle: Bundle.main)
}
return _model!
}
private static func loadModel(name: String, bundle: Bundle) throws -> NSManagedObjectModel {
guard let modelURL = bundle.url(forResource: name, withExtension: "momd") else {
throw CoreDataModelError.modelURLNotFound(forResourceName: name)
}
guard let model = NSManagedObjectModel(contentsOf: modelURL) else {
throw CoreDataModelError.modelLoadingFailed(forURL: modelURL)
}
return model
}
enum CoreDataModelError: Error {
case modelURLNotFound(forResourceName: String)
case modelLoadingFailed(forURL: URL)
}
public static func getContainer(iCloud: Bool) throws -> NSPersistentContainer {
let name = "LogModel"
if iCloud {
return NSPersistentCloudKitContainer(name: name, managedObjectModel: try model(name: name))
} else {
return NSPersistentContainer(name: name, managedObjectModel: try model(name: name))
}
}
}
Does anyone have any idea how I could solve this problem?
fairly new to SwiftUi still but have been struggling with finding a solution to this problem as well. By the looks of it I’ve been following all of the stackoverflow questions and answers as yourself.
For context I get a very inconsistent result between a iPad and a iPhone with a version of my code which is pretty close to mine, where sometimes it works and I can toggle on and off cloudkit.
However...
After playing around with the code and commenting on and off lines and reading some more, this line of code stood out as a question for me.
surely the answer is in its name. RemoteChangeNotificationPost.
what I have done its put that line in with the
so it only "Posts Changes" when iCloud is enabled.
now when I toggle off cloudkit. no updates are sent through.
When you toggle it back on, it does require a change to happen on the device to trigger a sync it seams but it I feel its a step closer to a result?
hit me down everyone if im doing anything wrong wouldn't want to be pushing a bad practice but so far.... it works till I find a better solution.
message from Apple: