Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

259
Visualizações
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 Respostas
Responde à pergunta

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda