قالب وردپرس درنا توس
Home / IOS Development / How to make a copy of a Core Data SQLite database – Ole Begemann

How to make a copy of a Core Data SQLite database – Ole Begemann



It is not trivial to create a copy (for example, for a backup) of an SQLite database file while used by Core Data:

  1. There are several files that conflict with: the main database file, the logbook (ends in -wal ) and the shared memory file (ends in -shm ).
  2. Creating a copy of the database file while a transaction is in progress can result in a corrupt copy.

You should use official Core Data APIs to create copies of the database. I do not know if Apple has an official test code for this task, but NSPersistent Large Coordinator. Migrate Permanent Store (_: to: options: withType :) seems to be the right method. I found it not very easy, but mainly because of this note in the documentation:

After calling this method, the specified store is removed from the coordinator such store is no longer a useful reference.

Since the goal is not to affect the source magazine (the active kernel data tray should remain usable), we must create a throwaway NSPersistentStore example whose sole purpose is to act as the source save for the copy function. I followed the strategy posted by Tom Harrington in a Stack Overflow Response:

  1. Create a New Migration Only NSP Resistant Large Coordinator and add the original store file. This will create a new NSPersistentStore example. (As far as I can tell, having two permanent stores working on the same database file is not a problem.)

  2. Use this new sustained store coordinator to transfer to the destination URL.

  3. add all references to the migration configurator.

Do this to make a backup:

  la    storeCoordinator :    NSPersistentStoreCoordinator    =    ... [1
9659017] makes
{ 19659018] backupFile = sample storeCoordinator backupPersistentStore ( atIndex . 0 ] defer { // Delete temporary directory when done try! backupFile . deleteDirectory () } [19659040] print [] [Backupon[19659041] " backupFile . fileURL .] ] // Do something with backupFile.fileURL // Move it to a fixed location, send it to the cloud, etc. // ... } [19659022] { print ( "Incorrect backup of the core data store: error ) ") }

Here is the code for backupPersistentStore (atIndex :) ):

  import    CoreData [19659064] import    Foundation 

  /// Safe copies the specified `NSPersistentStore` to a temporary file. 
  /// Useful for backups. 
  / // 
  /// - Parameter Index: Index of the Sustainable Store in the coordinator's 
  ///` PersistentStores` array. Passes an index that does not exist will capture. 
  /// 
  /// - Returns: The URL of the backup file, wrapped in a temporary file file 
  /// for easy deletion.    extension    NSPersistentStoreCoordinator    {
      FUNC    backupPersistentStore  (  atIndex    index :    Int )    casts    ] ->    TemporaryFile    {
          // Inspiration: https://stackoverflow.com/a/22672386
        // Documentation for NSPersistentStoreCoordinate.migratePersistentStore: 
          // "Upon invocation of this method, The specified [source] store is 
          // removed from the coordinator and hence no longer a useful reference. "
          // => Strategy: 
          // 1. Create a new" intermediate "NSPersistentStoreCoordinator and add 
          // the original store file. 
          // 2. Use this new PSC to migrate to a new file URL. 
          // 3. Delete all references to the intermediate 

] ( PersistentStores . Indexes . contains ( index ), ] index ) not found in persistentStore array ") la sourceStore = persistentStores [ index ] la backup coordinator = NSPersistentStoreCoordinator ( managedObjectModel : managedObjectModel ) ] With intermediateStoreOptions [19659015] = ( sourceStore . alternatives ?? [:]) . merger NSReadOnlyPersistentStoreOption : true ] uniquingKeysWith : { $ 1 [19659147]}) la intermediateStore = sample backupCoordinator [19659024] addPersistentStore ( ofType . sourceStore type configurationName . source store . configurationName at : sourceStore url the options . intermediateStoreOptions ] la backupStoreOptions : [ AnyHashable : Any ] = [ ] NSReadOnlyPersistentStoreOption : true // Disable log in advance. Advantage: The entire store will be // contained in a single file. You do not have to handle -wal / -shm files. // https://developer.apple.com/library/content/qa/qa1809/_index.html NSSQLitePragmasOption : [ "journal_mode" : ] "DELETE" ] // Minimize the file size NSSQLiteManualVacuumOption : true              ] ] [FileName:basenavn-datesqlite // Eg { { la base name -> = source store . url . deleting PathExtension () . loadPathComponent ?? "Save Backup" la dateFormatter = ISO8601DateFormatter () dateFormatter . formatOptions = [. with Year . withMonth . withDay . ] ] la dateString [19659015] = dateFormatter string ( from : Date ()) . ] (19459062] basename ) - ( dateString ) .sqlite " } [1 9659136] ] backupFileame = makeFilename () la backupFile = sample TemporaryFile ( creatingTempDirectoryForFilename [19659013] : backupFile ) try backupCoordinator migratePersistentStore ( intermediateStore to . backupfile ] backfile } options . backupStoreOptions withType : NSSQLiteStoreType }

The code uses TemporaryFile the help type I wrote about yesterday. You can download everything from GitHub. [19659287] Some things I especially like about the code:

  • The target store is configured with write-boosting logging disabled. This means that the entire store will be contained in a single .sqlite file. You do not have to handle the files -wal and -shm .
  • The target store has NSSQLite manual vacuum option enabled Thomas Krajacic asked if the method can handle Core-Data-Managed.

Both the source and the target group are configured read-only.

Update March 24, 2018: External binary data (ie attributes that you have selected option "Allows remote storage" in the model editor). It may – The temporary directory contain a hidden folder named . _SUPPORT next to the copied database file.

However, the feature does not report that there are more files to consider for the caller, so be sure to take care of themselves.

Disclaimer: This approach worked in my (limited) test, but I can not say that it is 100% safe in all situations. If you know better, I'd love to hear from you.

Update March 26, 2018: Drew McCormack wrote in :

A problem with the Core Data migration method used to be it would pull the whole store into memory. … Not sure if there is still a problem.

Me neither, but remember it as a potential problem if you have to deal with very large databases.




Source link