使用XCode 8 GM的iOS 10导致NSUserDefaults间歇性无法正常工作

时间:2016-09-12 19:36:32

标签: ios objective-c xcode nsuserdefaults ios10

注意:我在Stack Overflow上看到很多关于NSUserDefaults在Swift中重命名为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";
}

现在,如果我运行应用程序大约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

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

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

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

修改 错误记录:28287988

来自苹果DTS团队的回复:

  

首先,您应首先确定standardUserDefaults还是   valueForKey失败。我的猜测是“standardUserDefaults”   返回NULL,如果是这样的话,那就是你   一般应该防范。值得注意的是,standardUserDefaults   如果首选项文件在中加密,则返回NULL   应用程序当前正在运行的环境(例如,首选项   设置为“NSFileProtectionComplete”并且应用程序正在运行   背景)。这不应该是标准前景的问题   应用程序,但无论如何都要注意这一点。

     

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

2 个答案:

答案 0 :(得分:9)

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

  • 在Xcode 8和iOS 10的GM版本中发生。
  • 指向Swift的链接问题
  • 引用模拟器测试版的链接问题。

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

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

你应该report a bug to Apple,特别是因为你有一个可以重现它的短程序。我也会这样做。

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

答案 1 :(得分:0)

来自我自己的支持请求的同样非常智能的DTS响应。基本上,使用Xcode进行杀戮比在设备上自然发生的任何事情都更具杀气力(即使是双Home-click-and-upwipe方法),并且由于Xcode暂停时所有内容都突然崩溃,因此NSUserDefaults的懒惰写入可能会失败,或只完成一半。

事实上,在没有涉及Xcode的情况下对应用程序进行纯粹的设备上测试表明,当应用程序终止时,所有内容都会正确写入NSUserDefaults。

我已经关闭了自己的错误报告。