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

macOS Sequoia(15)下如何让NSSavePanel遵守setDirectoryURL设置?

macOS Sequoia(15) 下强制NSSavePanel遵守指定初始目录的问题

我的macOS应用通过NSSavePanel实现保存对话框,期望面板始终打开在函数参数指定的目录(如/User/Desktop)。简化代码如下:

- (NSURL *)doSave:(NSURL *)initialLocation
     withFileName:(NSString *)fileName
         withTitle:(NSString *)title
{
    NSSavePanel *_savePanel = [NSSavePanel savePanel];

    // 期望强制打开到此目录
    [_savePanel setDirectoryURL:initialLocation];
    [_savePanel setNameFieldStringValue:fileName];
    [_savePanel setTitle:title];

    if ([_savePanel runModal] == NSModalResponseOK) {
        return [_savePanel URL];
    }
    return nil;
}

在macOS Sonoma(14)及更早系统中,该代码可正常让对话框打开在initialLocation指定目录,但在macOS Sequoia(15)下,面板始终打开系统全局的上次文件保存位置,完全无视setDirectoryURL的设置。

我尝试过以下方法,但均无效:

  • 清除identifier(_savePanel.identifier = nil)
  • 设置_savePanel.restorable = NO
  • 清除NSUserDefaults中如NSNavLastRootDirectory的键值
  • 在runModal前重新设置directoryURL

通过LLDB调试发现:创建保存面板后,directoryURL为上次使用的文件夹;调用setDirectoryURL:initialLocation后,directoryURL直接变为nil。另外,使用已废弃的旧APIsetDirectory:时,面板可正常打开指定目录且不被系统覆盖,但显然不能依赖废弃API。

请问如何在macOS Sequoia(15)下强制NSSavePanel遵守setDirectoryURL设置?Apple是否更改了设置初始目录的方式?是否有新API或标志可禁用「上次使用文件夹」行为?


解决方案

在macOS Sequoia中,Apple对NSSavePanel的目录恢复逻辑做了调整,可通过以下几种有效方式强制指定初始目录:

  1. 调整代码顺序:先设置允许的文件类型,再指定目录URL
    Sequoia中,若未先设置allowedFileTypes,setDirectoryURL的设置可能被系统默认逻辑覆盖。调整代码顺序即可解决:

    - (NSURL *)doSave:(NSURL *)initialLocation
         withFileName:(NSString *)fileName
             withTitle:(NSString *)title
    {
        NSSavePanel *_savePanel = [NSSavePanel savePanel];
        // 先设置允许的文件类型(根据业务场景调整,比如@"txt"、@"pdf")
        [_savePanel setAllowedFileTypes:@[@"your-target-file-type"]];
        // 再指定初始目录
        [_savePanel setDirectoryURL:initialLocation];
        [_savePanel setNameFieldStringValue:fileName];
        [_savePanel setTitle:title];
        [_savePanel setRestorable:NO];
        [_savePanel setIdentifier:nil];
    
        if ([_savePanel runModal] == NSModalResponseOK) {
            return [_savePanel URL];
        }
        return nil;
    }
    
  2. 使用异步Sheet模式替代同步runModal
    部分开发者反馈,使用异步的Sheet展示方式时,系统的目录恢复逻辑不会干扰指定的初始目录。如果应用适配Sheet模式,可尝试这种方式:

    - (void)doSaveAsync:(NSURL *)initialLocation
           withFileName:(NSString *)fileName
               withTitle:(NSString *)title
          completion:(void(^)(NSURL *))completion
    {
        NSSavePanel *_savePanel = [NSSavePanel savePanel];
        [_savePanel setDirectoryURL:initialLocation];
        [_savePanel setNameFieldStringValue:fileName];
        [_savePanel setTitle:title];
        [_savePanel setRestorable:NO];
        [_savePanel setIdentifier:nil];
    
        [_savePanel beginSheetModalForWindow:[NSApp mainWindow] completionHandler:^(NSModalResponse result) {
            if (result == NSModalResponseOK) {
                completion([_savePanel URL]);
            } else {
                completion(nil);
            }
        }];
    }
    
  3. 提前校验初始目录的有效性
    Sequoia对无效目录URL的处理更严格,若initialLocation不存在或不可访问,会直接 fallback 到上次保存位置。可提前添加校验逻辑:

    BOOL isDir = NO;
    if (![[NSFileManager defaultManager] fileExistsAtPath:[initialLocation path] isDirectory:&isDir] || !isDir) {
        // 处理无效目录,比如 fallback 到用户桌面
        initialLocation = [NSURL fileURLWithPath:NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES).firstObject];
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 14:40:56