iOS 10与XCode 8 GM导致NSUserDefaults间歇性失效

17

注意: 我在Stack Overflow看到了许多有关NSUserDefaults被重命名为UserDefaults或在模拟器上无法工作直到重新启动的帖子。这不是任何重复的问题。很多SO标记的问题都是4年前的了。我的问题是针对今年的iOS 10具体情况,因为在旧版本中始终有效。我已经在我的问题中提到,我的问题不是那些问题的重复,因为那些是swift中的模拟器错误,而我的问题是设备上的objective C错误。请在标记为重复之前先阅读问题。

我的问题与众不同,因为我能够在objective 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次并再次失败等等。

现在,我注意到(虽然不确定百分之百),问题似乎只会在通过Xcode连接测试时发生。如果我通过单击设备上的应用程序图标启动应用程序而不使用Xcode运行,则似乎可以正常工作,但我不能百分之百确定。

我注意到有时会出现此错误:

[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,如果是这种情况,则通常应该加以防范。 值得注意的是,如果首选项文件在应用程序当前运行的环境中被加密(例如,“NSFileProtectionComplete”设置为首选项,并且应用程序正在后台中运行),则standardUserDefaults将返回NULL。 对于标准的仅前台应用程序,这不应该成为问题,但无论如何都需要注意。

很可能Xcode实际上引发了问题。 Xcode以非常不同于标准应用程序启动的方式大大复杂化了应用程序启动环境。 我猜这基本上是由Xcode的时序诱发了应用程序启动期间的预期情况,但如果您要更正式地测试它,请在applicationDidFinishLaunching中设置一个断点并在命中该断点后立即在调试器中继续进行。 我猜添加这个断点足以打乱时序,从而阻止问题发生。 有点像。 它只在iOS 10上存在,因为日志消息是在iOS 10中添加的,但这是因为日志消息是在iOS 10中添加的。 代码与iOS 9.3足够相似,以至于我认为在理论上iOS 9中可能会发生完全相同的行为。


1
可能是重复的问题:iOS 10,NSUserDefaults不起作用 - JAL
1
这个问题是重复的。仅仅因为链接问题上的答案没有帮助到你,并不意味着你的问题以前没有被问过。我看到你已经编辑了你的问题,说明你认为这不是一个重复的问题。希望有人能够解决你的问题。 - JAL
1
你显然没有阅读链接的问题,因为它与Swift无关。 - JAL
1
绝对不是其他问题的重复,其他问题要么涉及Swift语言更改,要么涉及iOS模拟器之间的不兼容性。这个问题可以在设备和模拟器上重现,并且确实是间歇性的。 - nugae
1
谢谢 @PranoyC,非常有用。 - Dan Marinescu
显示剩余13条评论
2个回答

9

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

  • 它发生在Xcode 8和iOS 10的GM版本中。
  • 这不是指涉到Swift的链接问题。
  • 这也不是指涉到模拟器beta版本的链接问题。

这个错误会在设备和模拟器上出现。它是间歇性的:保存将工作六次然后失败。与您不同的是,我没有收到“无法写入密钥”的消息。

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

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

一个关键的区别:在我的情况下,失败在于写入默认值。之前写入的值仍然存在于NSUserDefaults中。有时一个键成功写入而另一个键则保持不变。


谢谢更新!几分钟前我刚向苹果提交了一个DTS,现在我知道我不是唯一面临这个问题的人。如果他们认为这也应该是一个bug,那么这将是一个相当重要的bug,并会在应用程序中引起许多问题。 - sudoExclaimationExclaimation
1
我刚刚报告了一个28287988号错误,并且也记录了一个DTS。我会更新我发现的内容。 - sudoExclaimationExclaimation
这里是 Bug 28289469。 - nugae
我将苹果公司DTS团队对我的问题的回复添加了进来,如果你感兴趣的话! - sudoExclaimationExclaimation
你救了我剩下的头发!!!我已经连续几天都在想这到底是怎么回事,都快把头发都拔光了。我开始怀疑这是某种iOS的bug,因为一些不应该发生的事情正在发生。我有一个App在运行中,由于在AppDelegate初始化期间间歇性地未能将更改写入NSUserDefaults以支持对现有功能的更改而导致问题,用户们一直在抱怨。我已经尝试了三次,但仍然被我的用户们折磨着...至少现在我知道原因,并有更好的机会实施解决方法。 - Cliff Ribaudo

0

我自己的支持请求也得到了类似非常智能的DTS响应。基本上,使用Xcode杀死进程比设备上自然发生的任何事情都更加致命(即使是双击Home键并向上滑动的方法),由于Xcode停止时会突然崩溃所有内容,因此NSUserDefaults的懒惰写入可能会失败,或者只完成一半。

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

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


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