简述
最近在写的App是这种类型的,总结了总结,写了这篇博文,在掘金中没有客户端分类 我不知道该放到那个分类里 就放在iOS里吧
本文旨在介绍如何实现 基于文档的Mac App 若有描述不准确或错误的地方 还望多多指正,共同学习(๑•ᴗ•๑)
实现的效果也就是 在文档的打开方式中有自己的App可选,将文件拖拽至Dock栏中可以打开~
NSDocument
NSDocument
类相当于一层封装~ ,类似于UIImage
,无论是jpg格式还是png格式都以UIImage
对象进行调用~
NSDocument
则不仅可以对外持有 文档数据, 对内可以绑定 窗口控制器~.当打开文档时自动创建并展示与其绑定的窗口控制器~
Xcode提供的Document模板大概就是下面这个样子~
import Cocoa
class Document: NSDocument {
var saveData:Data!
//是否自动保存(出用户选择外的所有保存方式 都是非自动保存,像按钮..点击的方法中可以保存,其他的不能)
override class var autosavesInPlace: Bool {
return true
}
//用于为Document绑定WindowController,当打开新的Document时,对应的WindowController就会被打开~(不绑定也是可以的)
override func makeWindowControllers() {
let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController
self.addWindowController(windowController)
}
//将当前文档保存时调用
override func data(ofType typeName: String) throws -> Data {
Swift.print("保存文件")
return saveData
}
//当读取新的数据时调用
override func read(from data: Data, ofType typeName: String) throws {
saveData = data
Swift.print("读取内容 来自\(self.fileURL)")
}
//自动保存时调用的方法~ 当前是否能判断是否
override func autosave(withImplicitCancellability autosavingIsImplicitlyCancellable: Bool, completionHandler: @escaping (Error?) -> Void) {
Swift.print("调用自动保存")
//completionHandler(nil)
completionHandler(NSError.init(domain: "错误提示", code: 0, userInfo: nil))
}
}
复制代码
NSDocumentController
顾名思义是负责对Document
进行管理,是一个单例~ 方法也就主要是下面这些~
新建
NSDocumentController.shared.newDocument(nil)
//也可以直接init一个Document,然后加进去
复制代码
打开
//用户通过面板打开一个新的Document
NSDocumentController.shared.openDocument(nil)
//这里也可以使用NSDocument的init方法创建(使用的重载方法不同),但是这样创建的对象不再NSDocumentController的管理内~ 可以手动加入其中
复制代码
保存
//保存所有文档
NSDocumentController.shared.saveAllDocuments(nil)
//也可以调用NSDocument的save方法
复制代码
导出
这里应该调用的是 Document的 saveAs()/saveTo() 方法, 为了工整一些 我就放在这里了~
复制代码
info.plist配置
对NSDocument
类支持的文档类型和导出的文档类型是在 info.plist
中存储的~ 我们可以在Targets->info中进行设置~ 需要对Document Type和Export UTIs进行设置~~
这里就引入了一个概念UTI,它是Apple系统处理文档文件等数据的统一类型标识符,也可以把它理解为苹果爸爸对其他各类文档数据的别名,大家叫jpg
,苹果爸爸叫它public.jpeg
.除去UTI中约定好的部分,对于 我们自创的类型,则可以设置自创的别名~ 在这里我就使用已有类型了jpg
其他的UTI看这里Uniform Type Identifies
Document Types
Name: 文档的类型名称,可为空~
identifer: 文档标识,若是用自定义的类型,这里可以写自定义的类型.若是针对已有类型可以在UTI中找~
Class: 标识该类型对应在项目中的Document类,我使用的继承NSDocument
的子类 MK_Document,所以这里填 $(PRODUCT_MODULE_NAME).MK_Document
Roler: 这里表示应用对文档的处理权限, Editor(读写),Viewer(只读).
Extensions: 文档后缀,不区别大小写~
Icon: 自定义类型在Finder中显示的样子(有时候可以,有时候不行,就和我用Movist看mkv
视频,有时候可以带上Movist图标,有时候不行~ 要有懂这个图片设置的老铁 分享一蛤~)
至于其他的一些选项,我没用到
至于下面那个additional document type properties
是设置额外的文档属性,在旧版Xcode中Document Types在这里的选项并没有这么多,那个时候需要用它设置额外的一些属性,我用的Xcode9上面提供的选项已经够用了~~
当我们设置多个Document Type且绑定至同一个Document上时,在新建的文档保存/导出时,会让我们选择格式~
Export UTLs
若是App只是使用已有的文档类型如jpg
,则是在Document Types中设置就已经足够了,但是若要试用自定义类型的话,则需要用到
Description
外都是必填的~
identifer和Extension这里是自定以的~怎么写都好~ 但是上下要一致
Conforms To这里我填写的是public.data
,这里到底写什么,可以在UTIs中按需选择~
效果如下~~
FileWrapper
有些时候,我们的文档并非只是一个文档,还有类似于bundle
这种类型的文档包,(在这里吐槽一句,其实MarkDown也应该做成文档包这种样式就好了~) 效果如下
配置FileWrapper和上面略有不同~
infor配置
NSFileWrape
方法 其他地方也就是换汤不换药
//保存时调用
override func fileWrapper(ofType typeName: String) throws -> FileWrapper {
let fileWrappers = FileWrapper(directoryWithFileWrappers: [:])
return fileWrappers
}
//读取时调用~ 包中的数据可以通过 filleWraper获取
override func read(from fileWrapper: FileWrapper, ofType typeName: String) throws {
for item in fileWrapper.fileWrappers! {
Swift.print("获得\(item.key)")
}
}
复制代码
总结
NSDocument
是 对文档的封装,无论面对什么样的文档 都是NSDocument对象,和 NSData一样~ 这种设计方案是是值得我们借鉴的 尤其是在写SDK时~
若上文有不准确的地方 还望多多指正 共同学习 (๑•ᴗ•๑)