Mac沙箱创建成功但没有NSUserDefaults属性列表文件。

10

我正在追踪由沙盒创建引起的某些问题。在多种情况下,似乎NSUserDefaults .plist文件没有在Data/Library/Preferences中创建。我在调试器中和从Applications目录启动应用程序时都看到了这一点。我还没有尝试过归档、签名应用程序然后再启动。这是必须的吗?

以.LSSharedFileList.plist结尾的别名文件会被创建,但它指向自身,因此不存在。

我不知道它是否相关,但控制台报告:

appleeventsd[72]: <rdar://problem/11489077> A sandboxed application with pid ... checked in with appleeventsd, but its code signature could not be validated ( either because it was corrupt, or could not be read by appleeventsd ) and so it cannot receive AppleEvents targeted by name, bundle id, or signature. Error=ERROR: #100013  { "NSDescription"="SecCodeCopySigningInformation() returned 100013, -." }  (handleMessage()/appleEventsD.cp #2072) client-reqs-q

谢谢。

5个回答

17

这可能与NSUserDefaults的缓存有关吗?

在最近的OS X版本中,默认设置不会立即写入磁盘,因此您可能无法立即看到它们。您可能需要尝试手动同步首选项 - 参见NSUserDefaults Class Reference

 

在运行时,您使用一个NSUserDefaults对象从用户默认数据库中读取应用程序使用的默认值。为了避免每次需要默认值时都打开用户默认数据库,NSUserDefaults将信息缓存起来。同步方法会定期调用,以使内存中的缓存与用户的默认数据库保持同步。

虽然我认为即使在10.9中,这也可能无法立即将默认设置写入磁盘,因为现在还涉及一些缓存用户默认设置的守护进程。

同时还要检查:

从沙箱中的辅助应用程序读取NSUserDefaults

Objective-C NSUserDefaults缓存会防止另一个应用程序准确地读取更改

何时(不)滥用NSUserDefaults


33
如果在测试/调试时移动容器到垃圾桶中,请注意,cfprefsd(参见“活动监视器”)仍会保留对 .plist 的链接。清空垃圾桶并强制退出 cfprefsd(用户和根)。 - mahal tertin
3
我有相同的问题,使用XCode6和10.9.5版本。在杀死cfprefsd进程后,一切都恢复正常了。非常感谢Greg,他帮我避免了很多麻烦。 - user808667
在El Cap上,我不得不重新启动;尽管情况和症状相同。 - Hal Mueller
@mahaltertin 你是我的英雄!感谢你的提示! - Lukáš Kubánek
我使用了 @mahaltertin 给出的解决方案。在我的电脑上完全正常运行。但是,应用程序仍然被拒绝了,因为当他们测试我的应用程序时,该应用程序没有将 NSUserDefaults 值保存在他们的 Mac 上。那么我该怎么办? - swapnil patel

8

把这个问题转化成完整的答案, 以防被错过。在尝试了其他解决方案后,我才读到这个方法,只需要几次点击即可解决。

@greg 和 @mehals 在第一个解决方案的评论部分提供的答案,为我解决了这个问题,而且不需要更改任何代码。

从活动管理器中杀死cfprefsd程序就可以解决问题。


有人能详细解释一下这个解决方案到底在做什么吗?或者为什么要使用这个解决方案?谢谢。任何回复都将不胜感激。 - stan liu
在我的情况下,我正在测试应用程序并删除了沙盒容器文件夹。我收到了关于“访问应用程序容器之外的首选项”的错误,我认为这只是 cfprefsd 因为它想要的首选项文件不再存在而感到困惑。 - grahamparks

3

在花费大量时间后,我找到了一个非常简单的解决方案:

- (void)fixDefaultsIfNeeded{
    NSArray *domains = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
    //File should be in library
    NSString *libraryPath = [domains firstObject];
    if (libraryPath) {
        NSString *preferensesPath = [libraryPath stringByAppendingPathComponent:@"Preferences"];

        //Defaults file name similar to bundle identifier
        NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];

        //Add correct extension
        NSString *defaultsName = [bundleIdentifier stringByAppendingString:@".plist"];

        NSString *defaultsPath = [preferensesPath stringByAppendingPathComponent:defaultsName];

        NSFileManager *manager = [NSFileManager defaultManager];

        if (![manager fileExistsAtPath:defaultsPath]) {
            //Create to fix issues
            [manager createFileAtPath:defaultsPath contents:nil attributes:nil];

            //And restart defaults at the end
            [NSUserDefaults resetStandardUserDefaults];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
    }
}

我本来想说有没有NSPreferencesDirectory的定义,但是我检查了一下发现没有。 - greg
谢谢,这对我很有帮助! - mirap

2

当我删除我的应用程序容器目录,但是没有清空回收站时,在10.10上出现了这个问题。

在10.10上,如果容器目录仍然在回收站中,则可以始终重新创建应用程序的属性列表文件,并且如果回收站为空,则创建成功。

因此,解决方案(至少对于我的问题)是在测试时删除沙箱应用程序的容器目录后始终清空回收站。


1

Swift 2 解决方案

let settingsDefaults = NSUserDefaults.standardUserDefaults();    

func registerSettingsPlist() {
        let sourcePath = NSBundle.mainBundle().pathForResource("Settings", ofType: "plist");
        let appDocsDirURL = self.applicationDocumentsDirectory;
        let destinationPath = appDocsDirURL.path?.stringByAppendingString("/Settings.plist");
        if (!NSFileManager.defaultManager().fileExistsAtPath(destinationPath!)) {
            do {
                try NSFileManager.defaultManager().createDirectoryAtPath(appDocsDirURL.path!, withIntermediateDirectories: true, attributes: nil);
                try NSFileManager.defaultManager().copyItemAtPath(sourcePath!, toPath: destinationPath!);
            } catch let error as NSError {
                print ("Error: \(error.domain)")
            }
        }
        let settingsDic = NSDictionary(contentsOfFile: destinationPath!);
        NSUserDefaults.standardUserDefaults().registerDefaults(settingsDic as! [String : AnyObject]);
        self.settingsDefaults.synchronize();
    }


lazy var applicationDocumentsDirectory: NSURL = {
            let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask);
            return urls[urls.count-1];
}();

定义self.applicationDocumentsDirectorysettingsDefaults的含义,我认为它们是非常明显的东西,但为了完全清楚起见。 - Dima Deplov

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