我和我的团队一直在研究现有的,基于非文档的Cocoa应用程序.这是我们的第一个Cocoa应用程序,尽管到目前为止我们已经完成了许多iOS应用程序.
该应用程序确实应该是基于文档的,所以我已经开始尝试转换它.但是这里和那里的东西似乎没有用.例如,文件 - >打开菜单项被永久禁用(尽管我最终将文件 - >保存菜单项设置为启用;最初它不会启用).另外,虽然文件 - >关闭菜单项本身被禁用,但我可以单击红色X关闭窗口; 但是,当我通过X按钮关闭窗口时,我的NSDocument实现(SPDocumentInfo)中的dealloc方法不会被调用.我创建了一个样本,全新的基于文档的应用程序,仅用于比较; 当我在那里关闭一个窗口时,确实调用了SPDocument实现的dealloc方法(正如我所期望的那样).所以这让我很担心.
我在这里和那里做了很多改变的项目; 他们包括:
Made SPDocumentInfo在.h文件中扩展SPDocument:
@interface SPDocumentInfo : NSDocument <NSWindowDelegate>
在SPDocumentInfo中实现以下内容:
- (NSString *)windowNibName {
    return @"SPDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController {
    [super windowControllerDidLoadNib:aController];
}
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError {
    NSString *xml = [self toXml];
    return [xml dataUsingEncoding:NSUTF8StringEncoding];
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError {
    // will make this work later
    if ( outError != NULL ) {
        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
    }
    return YES;
}
编辑.plist文件以添加"文档类型".除其他外,定义"Cocoa NSDocument Class"="SPDocumentInfo".
修改SPDocumentInfo中的某些连接以匹配基于示例文档的应用程序中的连接.例如,在SPDocument.nib中,File的所有者(表示SPDocumentInfo)是Window的委托.
所以,我想知道在转换为基于doc的应用程序时是否还有其他类似的问题.或者,有没有关于如何做到这一点的指南?(我看了但找不到任何东西).或者我应该重新开始使用基于文档的新应用程序并尝试将所有内容改进其中?一般来说,有没有人有这方面的经验?
一个经常发现的建议是创建一个新的基于文档的应用程序并将所有现有代码移到那里。对于各种配置良好的大型工作区来说,这可能很麻烦。更不用说破坏版本控制了。
我采取了以下简单的步骤,它奏效了:
从这个生成的项目中,从 Info.plist 复制以下部分(使用普通文本编辑器打开文件):
<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <key>CFBundleTypeExtensions</key>
        <array>
            <string>mydoc</string>
        </array>
        <key>CFBundleTypeIconFile</key>
        <string></string>
        <key>CFBundleTypeName</key>
        <string>DocumentType</string>
        <key>CFBundleTypeOSTypes</key>
        <array>
            <string>????</string>
        </array>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>NSDocumentClass</key>
        <string>$(PRODUCT_MODULE_NAME).Document</string>
    </dict>
</array>
并将其粘贴到您自己项目中的 Info.plist 文件中。
将 Document.swift 从生成的基于文档的项目复制到您自己的项目中。
它包含一个方法:
override func makeWindowControllers() {
    // Returns the Storyboard that contains your Document window.
    let storyboard = NSStoryboard(name: "Main", bundle: nil)
    let windowController = storyboard.instantiateController(withIdentifier: "Document Window Controller") as! NSWindowController
    self.addWindowController(windowController)
}
它按照您的应用程序通常的方式创建一个新窗口。如果故事板只有一个窗口控制器,则“withIDentifier”字段可以包含任意内容。如果故事板中有更多窗口控制器,则标识符需要与新文档的正确窗口控制器相对应。
@Hans 的回答提供的一切都是正确的,但所需的最终更改是完全、愚蠢的微不足道的,但添加了基于文档的应用程序附带的大量功能:
在Main.storyboard文件中,该document元素有一个需要删除的额外属性:initialViewController="XXX-XX-XXX".
这可能是第二行的最后一件事。删除它,Save…菜单选项以及其他一些菜单选项将在默认情况下正确启用,并且应用程序将在启动时正确识别文档对象。
这更多的是一种意见,而不是直接答案,但如果您是 Mac 端和基于文档的应用程序的新手,那么阻力最小的路径肯定是从模板创建一个新的基于文档的 Xcode 项目并移动相关代码结束,将其插入模板需要的位置。