2017-09-02 1 views
1

J'ai une base de données de base de données que je souhaite pré-remplir sans avoir à charger toutes les données au premier lancement. J'essaye de faire ceci en créant une deuxième application qui s'occupe du chargement et copie la base de données SQL de cette application au nouveau. Dans un premier temps j'ai essayé de simplement copier le fichier .sqlite de la deuxième application et copiez les fichiers dans la première application comme ceci:Migration de la base de données de base d'une application à une autre

lazy var persistentContainer: NSPersistentContainer = { 
     let container = NSPersistentContainer(name: "GeoPointDB") 

     let seededData: String = "GeoPointDB" 
     var persistentStoreDescriptions: NSPersistentStoreDescription 

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

     if !FileManager.default.fileExists(atPath: (storeUrl.path)) { 
      let seededDataUrl = Bundle.main.url(forResource: seededData, withExtension: "sqlite") 
      try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl) 

     } 

     container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)] 
     container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
      if let error = error { 

       fatalError("Unresolved error \(error),") 
      } 
     }) 

     return container 

    }() 

Cependant, cela m'a donné un message d'erreur indiquant « Impossible d'ouvrir le fichier de base de données ». La recherche d'un peu je trouve cet article: https://developer.apple.com/library/content/qa/qa1809/_index.html

Je dos allé donc à la seconde application et a essayé d'exporter la base de données correctement en utilisant ce code:

let documents = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first! 
       do { 
        try context.persistentStoreCoordinator!.migratePersistentStore(context.persistentStoreCoordinator!.persistentStores.first!, to: documents, options: nil, withType: NSSQLiteStoreType) 
        print("Managed to save database file") 
       } catch let error as NSError { 
        print("Failed to save DB: \(error)") 
       } 

Mais quand je fais cela je reçois exactement même erreur à l'exportation que lorsque vous essayez de charger la base de données copiée à la première application: "Impossible d'ouvrir le fichier de base de données". Des conseils sur ce que je fais mal ou comment effectuer la migration de la base de données en utilisant iOS 10/11 et Swift 3/4?

Quelques informations supplémentaires qui pourraient être utiles:

  • Les deux applications ont le code standard CoreData de l'option "Utiliser Core Data" Xcode sur la création de projets
  • Le modèle CoreData (fichier .xcdatamodeld) dans la première application est copié à partir de la seconde application pour assurer qu'il n'y a pas d'incohérences
  • Je suis en mesure d'ajouter et de récupérer les données de la base de données de la deuxième application sans aucun problème

Répondre

1

Finalement, j'ai réussi à trouver une solution réalisable. Je n'ai toujours pas compris comment exporter correctement la base de données, mais comme je n'effectuerai cette migration qu'une seule fois pour chaque mise à jour (ou moins fréquemment), je peux copier manuellement les données et vérifier que la base de données n'est pas corrompue. soumettre à l'App Store.

En ce qui concerne le code pour l'importation de la base de données, ce que je fini par utiliser:

lazy var persistentContainer: NSPersistentContainer = { 
     let databaseName = "GeoPointDB" 

     let container = NSPersistentContainer(name: databaseName) 

     var persistentStoreDescriptions: NSPersistentStoreDescription 

     let storeUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!.appendingPathComponent(databaseName + ".sqlite") 
     let storeUrlFolder = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first! 

     if !FileManager.default.fileExists(atPath: (storeUrl.path)) { 
      let seededDataUrl = Bundle.main.url(forResource: databaseName, withExtension: "sqlite") 
      let seededDataUrl2 = Bundle.main.url(forResource: databaseName, withExtension: "sqlite-shm") 
      let seededDataUrl3 = Bundle.main.url(forResource: databaseName, withExtension: "sqlite-wal") 

      try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl) 
      try! FileManager.default.copyItem(at: seededDataUrl2!, to: storeUrlFolder.appendingPathComponent(databaseName + ".sqlite-shm")) 
      try! FileManager.default.copyItem(at: seededDataUrl3!, to: storeUrlFolder.appendingPathComponent(databaseName + ".sqlite-wal")) 

     } 

     container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)] 
     container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
      if let error = error { 

       fatalError("Unresolved error \(error),") 
      } 
     }) 

     return container 
    }() 

Les deux choses que je essentiellement changé était de faire en sorte que le NSPersistantStoreDescription pointait directement sur le fichier SQL (plutôt que son répertoire comme ci-dessus) et que j'ai copié tous les trois fichiers (.sqlite, .sqlite-shm et .sqlite-wal) dans le dossier de documents.