objective-ccore-dataios8.1nspersistentstore

I create a file using NSPersistentStoreCoordinator, but it's not found after app restart


I am trying to do a backup/restore of my Core Data store; in my app, I create the file, do a fileExistsAtPath and the file is there. When I use Finder, it's not there. This is the code (which I copied and modified, so the style and duplicate naming is not mine; probably should start all over again) to create the backup:

UPDATE The code is here...

This is the console output:

currentURL is file:///Users/spokanedude/Library/Developer/CoreSimulator/Devices/1EE69744-255A-45CD-88F1-63FEAD117B32/data/Containers/Data/Application/41B5E165-C3E2-4D8A-81EB-98ADB20B8B0D/Documents/saori.sqlite 2015-01-20 10:41:36.042 SalonBook[84743:2055509]

backup file URL to use is file:///Users/spokanedude/Library/Developer/CoreSimulator/Devices/1EE69744-255A-45CD-88F1-63FEAD117B32/data/Containers/Data/Application/41B5E165-C3E2-4D8A-81EB-98ADB20B8B0D/Documents/saori.backup-20153920103944

2015-01-20 10:41:36.042 SalonBook[84743:2055509]

currentCoreData exists 2015-01-20 10:41:36.042 SalonBook[84743:2055509]

backupFile exists 2015-01-20 10:41:36.042 SalonBook[84743:2055509]

target file exists 2015-01-20 10:41:36.092 SalonBook[84743:2055509] current store file removed

2015-01-20 10:41:36.125 SalonBook[84743:2055509] replaced current store file successfully

2015-01-20 10:41:36.126 SalonBook[84743:2055509] store Options are { NSSQLitePragmasOption = { "journal_mode" = WAL; }; } 2015-01-20 10:41:36.127 SalonBook[84743:2055509] addPersistentStoreWithType completed successfully...

2015-01-20 10:41:36.127 SalonBook[84743:2055509] STORE FILE is /Users/spokanedude/Library/Developer/CoreSimulator/Devices/1EE69744-255A-45CD-88F1-63FEAD117B32/data/Containers/Data/Application/41B5E165-C3E2-4D8A-81EB-98ADB20B8B0D/Documents/saori.sqlite

When I do the backup, it says the file is there; when I use ForkLift (a Finder replacement) it shows up (sometimes); when I do the restore, it finds the file and says the restore was successful, but instead it wipes out the existing data, like the file contents were missing. Can't figure this out for the life of me... help would be appreciated.


Solution

  • First, check the documentation of fileExistsAtPath:. You will see this warning:

    Attempting to predicate behavior based on the current state of the file system or a particular file on the file system is not recommended. Doing so can cause odd behavior or race conditions. It’s far better to attempt an operation (such as loading a file or creating a directory), check for errors, and handle those errors gracefully than it is to try to figure out ahead of time whether the operation will succeed.

    That's exactly what you are doing, and you are seeing unexpected behavior.

    When using WAL mode, most of the data you want is NOT in the "saori.sqlite" file, but in other files that SQLite will place in the same directory. The "saori.sqlite" file may in fact never be written to when using WAL mode. Apple Technical QA 1809 documents this, and there is more detail available in the SQLite documentation.

    For this and other reasons, it's generally a good idea to give each Core Data SQLite store it's own directory.

    If you attempt to copy the "saori.sqlite" file to a new location and open it using Core Data without the other files that store will be effectively empty. And you will go :(

    This is unfortunately what your restore implementation does. It takes the backup "saori.sqlite" file and copies it to a new location without the other files used by WAL mode. It then adds a new store using that location - but the WAL files are missing, so Core Data creates new ones. This results in data loss - your data never got moved, and Core Data created fresh files.

    The recommended way to perform a restore is just the reverse of the backup: use a migration.