Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

253
Views
CoreData: ¿Hay alguna manera de eliminar limpiamente la base de datos respaldada, después de la copia de seguridad de la base de datos a través de migratePersistentStore?

Actualmente, nuestra aplicación proporciona una funcionalidad de copia de seguridad al usuario, donde puede realizar una copia de seguridad instantánea de la base de datos de la aplicación.

Usamos migratePersistentStore para lograr dicha funcionalidad.

Después de ejecutar migratePersistentStore , ejecutaremos otras operaciones de E/S. Algunas de las operaciones de E/S pueden fallar. En tal caso, necesitamos eliminar completamente la base de datos respaldada.

Sin embargo, notamos que es muy difícil eliminar la base de datos respaldada.

Notamos que, en cierto punto, CoreData volverá a crear el archivo SQLite, aunque hayamos destroyPersistentStore y FileManager.default.removeItem .

Aquí está nuestro fragmento de código.

 public static func cloneXXXDatabase(dstUrl: URL, directory: Directory, cloneTrash: Bool) -> Bool { // Current already opened app database. let coreDataStack = CoreDataStack.INSTANCE guard let srcUrl = coreDataStack.persistentContainer.persistentStoreDescriptions.first?.url else { return false } // New destination to backup current app database. let coreDataNamedStack = CoreDataNamedStack(srcUrl) // Have a new NSPersistentStoreCoordinator solely for migration purpose. let psc = coreDataNamedStack.persistentContainer.persistentStoreCoordinator // Open the SQLite. Is it fine for 2 different NSPersistentStoreCoordinator to access 1 same SQLite? guard let srcStore = psc.persistentStore(for: srcUrl) else { return false } do { // Reference: https://www.avanderlee.com/swift/write-ahead-logging-wal/ // This is to ensure only 1 SQLite file is produced, without WAL & SHM. let options = [NSSQLitePragmasOption: ["journal_mode": "DELETE"]] try psc.migratePersistentStore(srcStore, to: dstUrl, options: options, withType: NSSQLiteStoreType) } catch { error_log(error) return false } // ... // ... (some other I/O operations) // ... var somethingWentWrong = true if somethingWentWrong { do { try psc.destroyPersistentStore(at: dstUrl, ofType: NSSQLiteStoreType) if dstUrl.exists { try FileManager.default.removeItem(at: dstUrl) } print(">>>> DELETE \(dstUrl)") // // WARNING: Such SQLite removal code is not working, and I am not sure why?! // It seems that after returning from this function, CoreData will still re-create the backup destination // DB, by logging // // CoreData: annotation: Connecting to sqlite database file at ".../xxx.sqlite". // } catch { error_log(error) } } return true }

¿Tiene idea de cómo podemos eliminar limpiamente el archivo SQLite, que se genera a través migratePersistentStore ? destroyPersistentStore y FileManager.default.removeItem no parecen funcionar.

Gracias.


Aquí está el código de CoreDataStack (pila de datos central para la aplicación principal) y CoreDataNamedStack (pila de datos central que apunta al destino de la copia de seguridad)

CoreDataStack (pila de datos central para la aplicación principal)

 class CoreDataStack { static let INSTANCE = CoreDataStack() private init() { } private(set) lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "xxx", managedObjectModel: NSManagedObjectModel.wenote) container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { // This is a serious fatal error. We will just simply terminate the app, rather than using error_log. fatalError("Unresolved error \(error), \(error.userInfo)") } }) // So that when backgroundContext write to persistent store, container.viewContext will retrieve update from // persistent store. container.viewContext.automaticallyMergesChangesFromParent = true return container }() }

CoreDataNamedStack (pila de datos central que apunta al destino de la copia de seguridad)

 class CoreDataNamedStack: CoreDataStackable { let url: URL init(_ url: URL) { self.url = url } private(set) lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "xxx", managedObjectModel: NSManagedObjectModel.wenote) let storeDescription = NSPersistentStoreDescription(url: url) container.persistentStoreDescriptions = [storeDescription] container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { // This is a serious fatal error. We will just simply terminate the app, rather than using error_log. fatalError("Unresolved error \(error), \(error.userInfo)") } }) // So that when backgroundContext write to persistent store, container.viewContext will retrieve update from // persistent store. container.viewContext.automaticallyMergesChangesFromParent = true return container }() }

Hallazgo

En lugar de ejecutar el siguiente código de eliminación inmediatamente

 var somethingWentWrong = true if somethingWentWrong { do { try psc.destroyPersistentStore(at: dstUrl, ofType: NSSQLiteStoreType) if dstUrl.exists { try FileManager.default.removeItem(at: dstUrl) } print(">>>> DELETE \(dstUrl)") } catch { error_log(error) } }

Si nos demoramos unos segundos antes de ejecutar código de borrado.

 var somethingWentWrong = true DispatchQueue.main.asyncAfter(deadline: .now() + 2) { if somethingWentWrong { do { try psc.destroyPersistentStore(at: dstUrl, ofType: NSSQLiteStoreType) if dstUrl.exists { try FileManager.default.removeItem(at: dstUrl) } print(">>>> DELETE \(dstUrl)") } catch { error_log(error) } } }

Entonces dicha eliminación tendrá éxito.

Supongo que CoreData tiene un subproceso de fondo que confirma cambios en el disco. Si la eliminación ocurre antes de que se confirmen los cambios en el disco, se volverá a crear el archivo de la base de datos.

¿Puedo saber cuál es la forma adecuada de resolver esto, sin tener un bloque de código retrasado arbitrario/aleatorio?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Observaciones que he anotado de sus fragmentos de código:

  1. Usó el método en desuso en NSPersistentStoreCoordinator . Documentación de Apple
  2. Para migrar de la URL de srcStore a dstStore, llevará tiempo migrar mediante migratePersistentStore() , por lo que debe verificar si la migración completa se completó antes de eliminar la base de datos respaldada.

Para hacerlo puedes comprobar el estado de la migración y destroyPersistentStore ple:

 let migrationResult = try psc.migratePersistentStore(srcStore, to: dstUrl, options: options, withType: NSSQLiteStoreType) if migrationResult { do { try psc.destroyPersistentStore(at: dstUrl, ofType: NSSQLiteStoreType) if dstUrl.exists { try FileManager.default.removeItem(at: dstUrl) } print(">>>> DELETE \(dstUrl)") // // WARNING: Such SQLite removal code is not working, and I am not sure why?! // It seems that after returning from this function, CoreData will still re-create the backup destination // DB, by logging // // CoreData: annotation: Connecting to sqlite database file at ".../xxx.sqlite". // } catch { error_log(error) } }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!