Should I delete underlying persistent store files after calling destroyPersistentStore on a NSPersistentStoreCoordinator?
Asked Answered
V

1

6

I'm migrating my iOS app to use NSPersistentContainer. This class by default locates its persistent store files in the Library/Application Support directory; previously my store files were stored in the Documents directory.

I've added a little bit of code to move the store files if they were found at the old directory:

func moveStoreFromLegacyLocationIfNecessary(toNewLocation newLocation: URL) {

    // The old store location is in the Documents directory
    let legacyStoreLocation = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("books.sqlite")

    // Check whether the old store exists and the new one does not
    if FileManager.default.fileExists(atPath: legacyStoreLocation.path) && !FileManager.default.fileExists(atPath: newLocation.path) {

        print("Store located in Documents directory; migrating to Application Support directory")
        let tempStoreCoordinator = NSPersistentStoreCoordinator()
        try! tempStoreCoordinator.replacePersistentStore(at: newLocation, destinationOptions: nil, withPersistentStoreFrom: legacyStoreLocation, sourceOptions: nil, ofType: NSSQLiteStoreType)

        // Delete the old store
        try? tempStoreCoordinator.destroyPersistentStore(at: legacyStoreLocation, ofType: NSSQLiteStoreType, options: nil)
    }
}

After calling destroyPersistentStore(at: url), the store files are still present on disk. Will these be automatically cleaned up at some point? Or should I be deleting them? Should I also be deleting the .sqlite-shm and .sqlite-wal files?

Vesiculate answered 10/2, 2018 at 15:42 Comment(0)
L
2

The documentation for NSPersistentStoreCoordinator.destroyPersistentStore(at:type:options:) states:

Deletes a specific type of persistent store at the provided location.

In talking with an engineer in a WWDC lab, they explained it does not actually delete the database files at the provided location as the documentation seems to imply. It actually just truncates rather than delete. If you want them gone you can manually delete the files (if you can ensure no other process or a different thread is accessing them).

This is what I've implemented in my app:

try coordinator.replacePersistentStore(at: sharedStoreURL, destinationOptions: nil, withPersistentStoreFrom: defaultStoreURL, sourceOptions: nil, ofType: NSSQLiteStoreType)
try coordinator.destroyPersistentStore(at: defaultStoreURL, ofType: NSSQLiteStoreType, options: nil)

// destroyPersistentStore says it deletes the old store but it actually truncates so we'll manually delete the files
NSFileCoordinator(filePresenter: nil).coordinate(writingItemAt: defaultStoreURL.deletingLastPathComponent(), options: .forDeleting, error: nil, byAccessor: { url in
    try? FileManager.default.removeItem(at: defaultStoreURL)
    try? FileManager.default.removeItem(at: defaultStoreURL.deletingLastPathComponent().appendingPathComponent("\(container.name).sqlite-shm"))
    try? FileManager.default.removeItem(at: defaultStoreURL.deletingLastPathComponent().appendingPathComponent("\(container.name).sqlite-wal"))
    try? FileManager.default.removeItem(at: defaultStoreURL.deletingLastPathComponent().appendingPathComponent("ckAssetFiles"))
})

I filed FB10181832 to request the documentation be updated to better explain its behavior.

Louielouis answered 11/6, 2022 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.