NSDocument 是 macOS AppKit 中用于构建文档类型应用(document-based app)的核心类。可以提供:
1、文件读写管理(open/save)。
2、窗口控制。
3、撤销/重做系统。
4、文档状态跟踪(是否修改)。
5、自动保存、版本控制。
可以认为它是 macOS 上“带有打开、保存等菜单项的文档型应用”的基础结构,比如:
1、Pages、Numbers。
2、Xcode(.xcodeproj)。
3、Preview(.pdf)。
4、Sketch、Photoshop(.sketch, .psd)。
5、自定义的图像编辑器、代码编辑器等。
基本功能
1、read(from:):打开文件时读取数据。
2、data(ofType:):保存文件时提供数据。
3、makeWindowControllers():创建并管理视图控制器和窗口。
4、自动保存、版本控制:与 macOS 文件系统(NSFileCoordinator)集成,支持状态感知、自动保存等。
5、支持撤销/重做:内置 NSUndoManager 支持。
6、多文档支持:一次打开多个窗口、多个文件(如 Xcode)。
常用属性
1、fileURL:URL?类型,当前文档的文件路径,可能为 nil(尚未保存)。
2、isDocumentEdited:Bool类型,文档是否被修改(显示小圆点)。
3、undoManager:UndoManager?类型,撤销管理器。
4、windowControllers:[NSWindowController]类型,当前文档的窗口控制器列表。
5、autosavesInPlace:Bool类型,支持自动保存到原位置,默认 true。
6、hasUnautosavedChanges:Bool类型,是否有尚未保存的更改。
7、fileType:String?类型,当前文件的类型标识,如 public.plain-text。
常用方法
1、makeWindowControllers()
用于创建和添加文档的窗口控制器(视图 UI):
override func makeWindowControllers() {
let wc = NSWindowController(windowNibName: "MyDocument")
self.addWindowController(wc)
}
通常配合 Interface Builder .xib 或 SwiftUI 的 NSHostingController 来构建界面。
2、read(from:ofType:)
打开文件时系统调用,用于“读取数据”:
override func read(from data: Data, ofType typeName: String) throws {
content = String(data: data, encoding: .utf8) ?? ""
}
可以将 Data 转为模型(字符串、JSON、图片、结构体等)。
3、data(ofType:)
保存文件时系统调用,用于“提供要保存的数据”:
override func data(ofType typeName: String) throws -> Data {
return content.data(using: .utf8) ?? Data()
}
配合 read(from:) 和 data(ofType:) 实现文件打开与保存功能。
4、save(_ sender: Any?)
手动保存调用,一般不需要 override,除非要做特殊行为。
5、canClose(withDelegate:shouldClose:contextInfo:)
用于拦截用户关闭窗口时的行为(提示保存):
override func canClose(withDelegate delegate: Any, shouldClose selector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
if isDocumentEdited {
// 弹窗提示保存
} else {
super.canClose(withDelegate: delegate, shouldClose: selector, contextInfo: contextInfo)
}
}
6、autosavesInPlace
系统会自动调用该属性判断是否自动保存:
override class var autosavesInPlace: Bool {
return true
}
7、updateChangeCount(_:)
当文档数据发生改变时,告知系统:
updateChangeCount(.done)
标记文档“已修改”,显示窗口标题上的小圆点。
8、fileWrapper(ofType:) 和 read(from:ofType:)
更复杂的文档结构可以使用 FileWrapper 处理目录、图像、多个数据文件等复合文档(如 Pages、Keynote)。
9、revert(toContentsOf:)
撤销文档内容到某个旧版本。
10、printOperation(withSettings:)
支持文档打印(可以自己构建一个 NSPrintOperation)。
文件支持
如果想要实现支持某种格式的文件,还需要配置Info.plist中的文件类型。
例如,支持 .txt 文件:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>Text Document</string>
<key>CFBundleTypeExtensions</key>
<array>
<string>txt</string>
</array>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>NSDocumentClass</key>
<string>MyDocument</string>
</dict>
</array>

配置Info.plist文件后,右击txt文件,就可以选择mac应用打开。

总结
NSDocument主要负责文件读写、状态管理。可以实现打开时读取数据,保存时提供数据。
支持macOS自动保存和恢复机制,默认集成NSUndoManager。