Working with file system on macOS. Part 2

Since my last post I kept tinkering with file system APIs.

Download full project

You can access the sample project on GitHub.

Learning materials and examples

Most of my questions are about the use of NSDocument, how to read it and how to write text files. Supporting desktop-class features in your iPad app is an excellent help and contained almost everything I need. There’s another example project which uses NSDocument: Developing a Document-Based App. For those who need to work with UIKit in addition to AppKit, I will repeat, the OSDocument approach from Nick Lockwood. There’s entire open source iPad code editor which I have found helpful as well/

I can read the content of any text files without using FileManager, by overriding NSDocument methods and storing text in the document.

Because I am not yet using NSTextEditor, I have to keep track of the changes using SwiftUI operators:

.onChange(of: text) { _ in
    save()
}

The save function can be implemented in many different ways. Here’s a working approach which seems to have no side effects. I also experimented with the autosave function but it didn’t work for me in the end, I would like to know why and what makes these 2 functions different. You also can use FileManager, but I think it defeats the purpose. The NSDocument also has a write function, luckily documentation says that it’s meant to be overridden and not called. Only the save function updates the file’s modification date properly, which allows OS to track changes.

file.updateChangeCount(.done)
file.save(self)

External changes

It is necessary to know about file content updates, likely, from a user using another text editor. NSDocument can detect when a file was modified externally and show the native dialogue.

Alert This document's file has been changed by another application since you opened or saved it Save or Don't Save

There’s also a different version of this dialogue with “Revert” and “Save As…” options. In my sample application only the “Save Anyway” button works. Reverting does nothing, and “Save As” causes a hang. I suspect it is somehow related to the autosave.

DispatchSource issue

My sample project uses DispatchSource to watch changes made in the root folder and changes made in the file itself. It works well for me when a name can change or when a file is deleted. However, monitoring content changes is not that reliable. Unlike the FileWatcher library, it stops working after some time, and the only fix is to select the root folder in the open dialogue and save a new secure bookmark.

The save dialogue allows me to ignore content changes and let the user override changes which were made externally with the “Save” button.

Permission issues

I had this one issue which caused writing errors.

Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “markdown” in the folder “new”." UserInfo={NSFilePath=/Users/boris/Pictures/new/markdown.md, NSUnderlyingError=0x60000031d950 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

After trying various things, I have found the root cause in the Signing & Capabilities project settings. All I needed to change is to set the User Selected File to “Read/Write” instead of “Read”.

Xcode target preferences File Access User Selected File Read/Write