注意: 我在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中可能会发生完全相同的行为。