You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于NSDocument的应用如何在NSSavePanel中设置默认选中文件类型

问题描述

配置信息截图
我正在使用NSDocument类开发一款简单的文档类应用,我的info.plist中配置了四个文档内容类型标识符,包括public.text、public.plain-text、public.source-code、public.rtf,如上图所示。调用NSSavePanel保存面板时,会列出所有上述文件类型,如下图所示:
保存面板截图
我的问题是:是否可以通过代码指定保存面板弹出时默认选中的文件类型?我希望保存面板出现时默认选中「富文本(RTF)」类型。
以下是我的NSDocument子类的部分代码:

import Cocoa

class Document: NSDocument {
    override init() {
        super.init()
    }

    override class var autosavesInPlace: Bool {
        return false
    }
    
    override func save(withDelegate delegate: Any?, didSave didSaveSelector: Selector?, contextInfo: UnsafeMutableRawPointer?) {
        if let _ = fileURL {
            print("Saved!!!")
        } else {
            print("Not saved yet...")
            NSApp.sendAction(#selector(NSDocument.saveAs(_:)), to: nil, from: self)
        }
    }
    
    override func writableTypes(for saveOperation: NSDocument.SaveOperationType) -> [String] {
        return super.writableTypes(for: saveOperation)
    }
    
    override func prepareSavePanel(_ savePanel: NSSavePanel) -> Bool {
        savePanel.allowsOtherFileTypes = true
        savePanel.isExtensionHidden = false
        
        guard let accessoryView = savePanel.accessoryView else { return true }
        for sub in accessoryView.subviews {
            print("Class: \(sub.className)")
            /*
            if sub.isKind(of: NSPopUpButton.self) {
                if let popUpButton = sub as? NSPopUpButton {
                    popUpButton.selectItem(at: 5)
                    print("Sure")
                }
            }
            */
            
        }
        return true
    }
}

我看到有一个类似主题的问题,其中使用了IKSaveOptions实现默认类型选择,但根据官方文档说明,该类仅适用于图像数据保存场景,而我的应用是文本类应用,不适用该方案,请问该如何实现需求?


解决方案

你不需要通过遍历保存面板私有子视图的方式修改选中项,这种方案依赖系统内部视图结构,系统版本更新后很容易失效,以下是两种官方支持的实现方式:

方式1:调整可写类型顺序(兼容所有 macOS 版本)

NSSavePanel 默认会选中 writableTypes(for:) 方法返回数组的第一个对应的文件类型,你只需要调整返回数组的顺序,把 RTF 对应的 UTI 放到第一位即可:

override func writableTypes(for saveOperation: NSDocument.SaveOperationType) -> [String] {
    let allTypes = super.writableTypes(for: saveOperation)
    // 把RTF类型移到数组首位
    guard let rtfIndex = allTypes.firstIndex(of: "public.rtf") else {
        return allTypes
    }
    var orderedTypes = allTypes
    let rtfType = orderedTypes.remove(at: rtfIndex)
    orderedTypes.insert(rtfType, at: 0)
    return orderedTypes
}

方式2:直接设置选中内容类型(适用于 macOS 11+)

如果你的应用最低支持 macOS 11,可以直接在 prepareSavePanel 中设置 selectedContentType 属性实现指定默认类型,逻辑更直观:
首先在文件头部导入 UniformTypeIdentifiers 框架:

import UniformTypeIdentifiers

然后修改 prepareSavePanel 方法:

override func prepareSavePanel(_ savePanel: NSSavePanel) -> Bool {
    savePanel.allowsOtherFileTypes = true
    savePanel.isExtensionHidden = false
    
    // 直接指定默认选中的RTF类型
    if let rtfType = UTType("public.rtf") {
        savePanel.selectedContentType = rtfType
    }
    
    return true
}

内容的提问来源于stack exchange,提问作者El Tomato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 06:57:03