NSSavePanel在应用沙盒化后无法保存文件

8
我正在使用NSSavePanel保存字符串文件时遇到问题,在将应用提交到Mac App Store之前,需要进行沙盒化。我已将com.apple.security.files.user-selected.read-write设置为YES,并且NSOpenPanel正常工作。
然而,当我尝试保存新文件时,似乎一切都运行良好,但是在应该保存的位置上却没有保存的文件......
以下是我用于保存文件的代码:
NSSavePanel *save = [NSSavePanel savePanel];

long int result = [save runModal];

if (result == NSOKButton)
{
    NSString *selectedFile = [save filename];
    NSString *fileName = [[NSString alloc] initWithFormat:@"%@.dat", selectedFile];
    NSString *arrayCompleto = [[NSString alloc]initWithFormat:@"bla bla bla"];
    [arrayCompleto writeToFile:fileName
                    atomically:NO
                      encoding:NSUTF8StringEncoding
                         error:nil];
}
1个回答

11

首先,-[NSSavePanel filename] 选择器已经被弃用。请使用 -[NSSavePanel URL] 代替。其次,-[NSString writeToFile:atomically:encoding:error] 如何告诉你哪里出了问题是通过 error:(NSError**) 参数。

特别是对于文件I/O的错误情况,您应该处理这些错误,因为即使您的代码是100%正确的,用户的系统上仍可能会出现错误(权限不足等)。向用户展示错误将使他们知道操作失败(并且有一些了解原因)。在代码中处理错误也将允许您的应用程序进行恢复。例如,如果您尝试在写入磁盘之后的代码中读取文件,但用户尝试将其写入无法访问的网络共享,则您的应用程序可能会崩溃。如果您知道写入失败,您可以相应地进行操作(例如提示用户选择不同的保存位置)。

在这种情况下,我认为以下行是您的问题:

NSString *fileName = [[NSString alloc] initWithFormat:@"%@.dat", selectedFile];

当你的应用程序被沙盒化时,用户需要通过打开/保存面板为您授予对特定文件特定目录的权限,以将它们引入您的沙盒中。您所做的是获取用户授权写入的文件,并说“很好,但我想保存不同的文件”,这违反了沙盒的规定。相反,您应该在保存面板中设置扩展名。完整的修复解决方案如下:

NSSavePanel *save = [NSSavePanel savePanel];
[save setAllowedFileTypes:[NSArray arrayWithObject:@"dat"]];
[save setAllowsOtherFileTypes:NO];

NSInteger result = [save runModal];

if (result == NSOKButton)
{
     NSString *selectedFile = [[save URL] path];
     NSString *arrayCompleto = @"bla bla bla";

     NSError *error = nil;
     [arrayCompleto writeToFile:selectedFile
                     atomically:NO
                       encoding:NSUTF8StringEncoding
                          error:&error];
}

if (error) {
    // This is one way to handle the error, as an example
    [NSApp presentError:error];
}
如果将来出现其他问题,您可以在运行时检查error的值。在调试过程中,设置断点在if (error)语句内以检查error对象的值(在Xcode的调试器中输入po error)。这应该可以帮助您找出问题所在。

没问题。我也忘了提到,无论何时处理文件I/O,处理错误都是特别好的实践,因为即使您的代码100%正确,在用户系统上可能会出现问题(权限不足等)。我已将其添加到答案中。 - Dov
您还可以设置提示保存的文件名,以避免保存为“未命名”文档:[save setNameFieldStringValue:@"MySuggestedFilename"] - David Douglas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接