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

注意:我已经看到堆栈溢出的许多其他职位关于NSUserDefaults被重命名为Swift的UserDefaults或不工作在模拟器上,直到重新启动。 这不是重复的。 SO所标注的许多问题都来自4年前。 我的问题是从今年开始专门针对iOS 10,因为这一直在旧版本中工作。 我已经在我的问题中提到过,我的问题不是那些模拟器错误的问题,我的问题是在设备客观的C错误。 请在标记为重复之前阅读这些问题

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

我为这个testing从头开始创build一个全新的项目。 我把这个代码放在视图控制器的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 ,有时它不。 没有确切的数字,它失败了多less次,因为它可能会工作3次,然后失败2次,然后工作4次,失败一次等。

现在我已经注意到(不是100%肯定),这个问题似乎只是在我通过Xcodetesting连接时发生的。 如果我通过点击没有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 

如果你想testing一下,我的Dropbox上有这个非常简单的项目。 我build议testing10-15次以重现此问题。

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

这在iOS 9上运行得非常好,所以绝对是与iOS 10有关的。

编辑 错误logging:28287988

来自苹果DTS团队的回应:

首先,您应该先确定standardUserDefaults或valueForKey是否失败。 我的猜测是,“standardUserDefaults”返回NULL,如果是这样的话,那么这是你应该防范一般。 值得注意的是,如果首选项文件在应用程序当前正在运行的环境中encryption(例如,首选项设置为“NSFileProtectionComplete”,应用程序在后台运行),standardUserDefaults将返回NULL。 这不应该是标准的前景应用程序的问题,但它是要注意的东西。

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

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

  • 它发生在Xcode 8和iOS 10的通用版本中。
  • 不是提到Swift的链接问题。
  • 不是涉及模拟器testing版的链接问题。

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

在没有Xcode的情况下直接在设备上运行时也会出现这个错误。 这其实是我发现的。

你应该向苹果报告一个bug ,特别是因为你有一个短的程序,将重现它。 我也会这样做。

一个关键的区别:在我的情况下,失败是在写作默认。 先前写入的值保留在NSUserDefaults中。 有时一个密钥成功写入,另一个密钥不变。

从我自己的支持请求类似非常聪明的DTS响应。 基本上,使用Xcode进行杀戮比任何自然发生在设备上的杀戮(甚至是双击主页上的和双击的方法),并且由于Xcode停止时一切都会突然崩溃,所以NSUserDefaults的延迟写入可能会失败,或者只完成一半。

事实上,没有涉及Xcode的应用程序纯粹的设备上testing显示,当应用程序终止时,一切都会正确写入NSUserDefaults。

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