NSFileCoordinator & NSFilePresenter

Context

I'm using the NSFileCoordinator & NSFilePresenter in a sandboxed application to access SQLite database files and their secondary files (e.g. WAL or journal files) as per https://developer.apple.com/documentation/foundation/nsfilepresenter/1415415-primarypresenteditemurl

E.g. something similar to this:

var presenters: [NSFilePresenter] = ["wal", "journal", "shm"].map { ext in
    let presenter = SQLiteTempFilePresenter(databaseId: databaseContext.id, sqliteMainFile: url, newExt: ext)
    // addFilePresenter needs to be balanced with a `removeFilePresenter`. See SQLiteTempFilePresenter#deinit
    NSFileCoordinator.addFilePresenter(presenter)
    return presenter
}

That way there will be a NSFilePresenter for each possible secondary SQLite file (e.g. with the main file being foo/bar/database.sqlite there will be presenter for each of the secondary files foo/bar/database.sqlite-shm and foo/bar/database.sqlite-wal)

Using NSFilePresenter to work with SQLite files within the Sandbox environment works as expected.

Desired change

I'd like to expand the usage of NSFileCoordinator to react to changes to the SQLite files that happen outside of the application. To achieve that I added an additional NSFilePresenter for the main file (e.g. foo/bar/database.sqlite) that has a func presentedItemDidChange() method. That method does get called when I change the corresponding SQLite file (e.g. by using the sqlite3 command line tool).

So far so good. But in WAL mode (https://www.sqlite.org/wal.html), changes to the SQLite file don't immediately change the file itself but get written to the write-ahead-log first (e.g. foo/bar/database.sqlite-wal in this example). Only when the outside connection is closed, will the changes be committed to the main SQLite file itself. At which point the NSFilePresenter#presentedItemDidChange() method will be called. So I also like to be notified when the secondary files change.

Adding a presentedItemDidChange() callback method to the SQLiteTempFilePresenter instances for the secondary files does not seem to work, the method never gets called even though the corresponding secondary files change.

Questions

  • If I add another instance of the NSFilePresenter for each of the secondary files, the callback presentedItemDidChange() gets called for the secondary files as well. Having two different instance of the NSFilePresenter for a single URL (one for sandboxing purposes, the other for being notified of file changes) seems a bit fishy though. Is that the intended (or at least an acceptable) way of using NSFilePresenter?

  • The documentation for NSFilePresenter states that "If another process uses a file coordinator for the same file or directory, your presenter objects are similarly notified whenever the other process makes its changes." I do get notified though when using the sqlite3 command line tool which does not use a NSFileCoordinator. Is there any documentation that explains that behaviour? I mean it's great that it seems to work but I'd like to understand why.

NSFileCoordinator & NSFilePresenter
 
 
Q