在 Swift 中覆盖 NSDocument 的 init(contentsOf:ofType:)

102*_*4jp 5 cocoa nsdocument swift

背景:

关于基于文档的 Cocoa 应用程序,Apple 建议覆盖 NSDocumentinit(contentsOf:ofType:)来自定义内容,因此似乎是一个覆盖的好地方。

您可以覆盖此方法以自定义重新打开自动保存的文档。

参见 init(contentsOf:ofType:) - NSDocument | 苹果开发者文档

然而在 Swift 上,这实际上是不可能的,因为 superinit(contentsOf:ofType:)不能被调用,init(contentsOf:ofType:)因为这个初始化器是方便的初始化器之一。

convenience init(contentsOf url: URL, ofType typeName: String) throws {

    try super.init(contentsOf: url, ofType: typeName)  // <- this marked as error
}
Run Code Online (Sandbox Code Playgroud)

我想要的是:

当我在Objective-C中编写基于文档的应用程序时,我使用这种方法,即initWithContentsOfURL:ofType:error:只为使用现有文件打开的文档准备一些文件相关的属性,而不为新的空白文档或恢复的文档准备一些文件相关的属性。

它不能简单地用 NSDocument 代替,read(from:ofType)因为它不仅会在文档打开时被调用,而且在每次重新加载文档时都会被调用(例如 Revert)。

也不可能在 normal 上做我的事情init(),因为fileURL当时还没有设置属性。

init() {
    super.init()

    self.fileURL  // <- returns nil
}
Run Code Online (Sandbox Code Playgroud)

我知道一个方便的初始化程序必须调用一个指定的初始化程序,但是init(contentsOf:ofType:)init(type:). (如何在 Swift 中初始化一个新的 NSDocument 实例?

像这样的东西?(但不确定)

 convenience init(contentsOf url: URL, ofType typeName: String) throws {
    self.init()

    self.fileURL = url
    self.fileType = typeName
    self.fileModificationDate = (try? FileManager.default.attributesOfItem(atPath: url.path))?[.modificationDate] as? Date
}
Run Code Online (Sandbox Code Playgroud)

题:

所以,我的问题是:在打开文档时只对 fileURL 做一次操作的合适点在哪里?

解决方法1:

对于解决方法,我目前覆盖makeDocument(withContentsOf:ofType:了 NSDocumentController 子类,并从原始文档的初始值设定项中创建一个文档,在其中self.init(contentsOf: url, ofType: typeName)调用。

解决方法2:

我上面提到的第一个解决方法并不安全。我发现最好在单独的函数中进行额外的初始化。

override func makeDocument(withContentsOf url: URL, ofType typeName: String) throws -> NSDocument {

    let document = try super.makeDocument(withContentsOf: url, ofType: typeName)

    (document as? Document)?.additionalInit()  // call original func

    return document
}
Run Code Online (Sandbox Code Playgroud)

Vol*_*ker 1

据我所知,这绝对是当前 Swift 的一个缺点,在 Swift 开发中也有讨论。然而,覆盖可以很容易地实现。从 Apple 文档中可以清楚地看出,read(from:, typeName)被称为 和fileURLfileType并且fileModificationDate被设置。这是一些简单的调用,例如:

convenience init(contentsOf url: URL, ofType typeName: String) throws {
    self.init()
    try self.read(from:url, ofType:typeName)
    self.fileURL = url
    self.fileType = typeName
    self.fileModificationDate = Date()
    //methods and sets values for the fileURL, fileType, and fileModificationDate properties.
    self.undoManager?.disableUndoRegistration()
    self.initializeGroups(false)
    self.managedObjectContext?.processPendingChanges()
    self.undoManager?.enableUndoRegistration()
}
Run Code Online (Sandbox Code Playgroud)

我刚刚开始一个NSPersistentDocument子类,目前效果很好。