Post

Replies

Boosts

Views

Activity

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.
0
0
487
Nov ’23
NSFileCoordinator with SQLite library
Context I'm using https://github.com/stephencelis/SQLite.swift as the access layer for interacting with SQLite databases. For each database I maintain a long running connection. As reading the schema is done lazily on each connection and can be expensive I prefer to open the connection once, do a number of operations and then close the connection when it is not needed any more (and given that the app is a GUI for working with SQLite databases, long running means long running). E.g. func open(url: URL, options: ...) func commitCurrentTransaction() throws func rollbackCurrentTransaction() throws func executeStatements(rawSQL: RawSQL, executeMode: ExecuteMode) async throws -> SQLOperationResult ... func close() To be a good citizen on the Mac I'm looking to use the NSFileCoordinator to indicate read and write operations on the SQLite database files the application is using. I'm thinking of wrapping each operation that might result in a file access with the corresponding coordinate(readingItemAt: ... and coordinate(writingItemAt: ... calls. But the API documentation states that the last argument, the block byAccessor should use the given URL: A Block object containing the file operations you want to perform in a coordinated manner. This block receives an NSURL object containing the URL of the item and returns no value. Always use the URL passed into the block instead of the value in the url parameter. In my case, the URL is used once when opening the connection but not afterwards so I'd be ignoring the URL passed to the block. The examples I have found for using the NSFileCoordinator seem to follow a different pattern, where the entire operation on the file happens within the block of the coordinate method. Questions What is the correct way of using NSFileCoordinator in a case like this where there essentially is a long live file handle in use? The application does work without using the NSFileCoordinator. What is the ramification of not using the NSFileCoordinator in this case?
1
0
393
Nov ’23