带有XCode 8 GM的iOS 10导致NSUserDefaults间歇性地无法正常工作

Pra*_*y C 17 xcode objective-c nsuserdefaults ios ios10

注意:我在Stack Overflow上看到很多关于在Swift NSUserDefaults中重命名的帖子UserDefaults或者在重启之前没有在模拟器上工作.无论如何,这不是重复.SO标记的许多问题来自4年前.我的问题是今年特定于iOS 10的,因为它一直适用于旧版本.我已经在我的问题中提到我的问题不是那些问题的重复,因为那些是swift中的模拟器错误,我的问题是设备目标C bug.请在标记为重复之前阅读问题

我的问题不同,因为我能够在目标C和物理设备本身上重现这一点.

我从零开始为这个测试创建了一个全新的项目.我将此代码放在viewDidLoad视图控制器中:

if (![[NSUserDefaults standardUserDefaults] valueForKey:@"checkIfInitialized"]){
    NSLog(@"setting checkIfInitialized as not exist");
    [[NSUserDefaults standardUserDefaults] setValue:@"test" forKey:@"checkIfInitialized"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    self.view.backgroundColor=[UIColor redColor];
    self.mylabel.text=@"NSUserDefaults was NOT there, try running again";
} else {
    NSLog(@"checkIfInitialized exists already");
    self.view.backgroundColor=[UIColor blueColor];
    self.mylabel.text=@"NSUserDefaults was already there this time, try running again";
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我运行应用程序大约10次,几次它找到了checkIfInitialized,有时它没有.没有确切的数字,它失败了多少次因为它可能会工作3次然后失败2次然后工作4次而失败一次等等.

现在事情我已经注意到(虽然肯定不是100%),这一问题似乎只当我测试通过Xcode的连接发生.如果我通过点击没有Xcode的设备上的应用程序图标启动应用程序来运行,那么它似乎工作正常,但我无法100%确定.

我注意到有时出现这个错误:

[User Defaults] Failed to write value for key checkIfInitialized in CFPrefsPlistSource<0x1700f7200> (Domain: com.xxxx.appname, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null)): Path not accessible, switching to read-only
Run Code Online (Sandbox Code Playgroud)

如果你想测试它,我在我的Dropbox上有这个非常简单的项目.我建议测试大约10-15次来重现这个问题.

https://www.dropbox.com/s/j7vbgl6e15s57ix/nsuserdefaultbug.zip?dl=0

这在iOS 9上完全正常,所以肯定与iOS 10有关.

编辑 错误记录:28287988

来自Apple DTS团队的回复:

首先,您应首先确定standardUserDefaults或valueForKey是否失败.我的猜测是"standardUserDefaults"返回NULL,如果是这样的话,那么你应该防范这一点.值得注意的是,如果首选项文件在应用程序当前运行的环境中加密,则standardUserDefaults将返回NULL(例如,首选项设置为"NSFileProtectionComplete",应用程序在后台运行).对于标准的仅限前景的应用程序来说,这应该不是问题,但无论如何都要注意这一点.

Xcode很可能实际上是在这里引发问题.Xcode以一种与标准应用程序发布非常不同的方式使应用程序启动环境变得非常复杂.我的猜测是,这基本上是由Xcode的时间触发引起应用程序启动期间的预期情况,但是如果你想要更正式的测试,尝试在applicationDidFinishLaunching中设置一个断点并在你点击它时继续调试器.我的猜测只是补充说,它会破坏时间,足以阻止问题的发生.有点.它只是iOS 10,因为iOS 9永远不会打印该日志消息,但那是因为日志消息是在iOS 10中添加的.代码本身与iOS 9.3类似,我怀疑行为完全相同(至少在理论)可以在iOS 9中使用.

nug*_*gae 9

是的,这绝对是一个可以重现的错误.

  • 它发生在Xcode 8和iOS 10的GM版本中.
  • 不是涉及Swift的链接问题.
  • 不是涉及模拟器的beta版本的链接问题.

该错误发生在设备和模拟器上.它是间歇性的:保存将工作六次然后失败.与你不同,我没有得到"写密钥失败"的消息.

直接在没有Xcode的设备上操作时也会发生错误.这实际上就是我发现它的方式.

您应该向Apple报告错误,特别是因为您有一个可以重现它的简短程序.我也会这样做.

一个关键的区别:在我的情况下,失败是写入默认值.先前写入的值仍保留在NSUserDefaults中.有时一个键成功写入而另一个键未更改.