NSUserDefaults在iOS 8中不可靠

Hae*_*nal 32 objective-c nsuserdefaults ios ios8

我有一个使用[NSUserDefaults standardUserDefaults]存储会话信息的应用程序.通常,此信息会在应用启动时检查,并在应用退出时更新.我发现它似乎在iOS 8中不可靠.

我目前正在iPad 2上进行测试,但如果需要,我可以在其他设备上进行测试.

有些时候,退出之前写入的数据不会在应用程序启动时持续存在.同样,在退出之前删除的键有时在启动后似乎存在.

我编写了以下示例,试图说明问题:

- (void)viewDidLoad 
{
    [super viewDidLoad];

    NSData *_dataArchive = [[NSUserDefaults standardUserDefaults] 
                                            objectForKey:@"Session"];

    NSLog(@"Value at launch - %@", _dataArchive);

    NSString *testString = @"TESTSTRING";
    [[NSUserDefaults standardUserDefaults] setObject:testString 
                                           forKey:@"Session"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    _dataArchive = [[NSUserDefaults standardUserDefaults] 
                     objectForKey:@"Session"];

    NSLog(@"Value after adding data - %@", _dataArchive);

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"Session"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    _dataArchive = [[NSUserDefaults standardUserDefaults] 
                     objectForKey:@"Session"];

    NSLog(@"Value before exit - %@", _dataArchive);

    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

运行上面的代码,我(通常)得到下面的输出(这是我所期望的):

Value at launch - (null)
Value after adding data - TESTSTRING
Value after deleting data - (null)
Run Code Online (Sandbox Code Playgroud)

如果我然后注释掉删除键的行:

//[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"Session"];
//[[NSUserDefaults standardUserDefaults] synchronize];
Run Code Online (Sandbox Code Playgroud)

并运行应用程序三次,我希望看到:

Value at launch - (null)
Value after adding data - TESTSTRING
Value after deleting data - TESTSTRING

Value at launch - TESTSTRING
Value after adding data - TESTSTRING
Value before exit - TESTSTRING

Value at launch - TESTSTRING
Value after adding data - TESTSTRING
Value before exit - TESTSTRING
Run Code Online (Sandbox Code Playgroud)

但我实际看到的输出是:

Value at launch - (null)
Value after adding data - TESTSTRING
Value after deleting data - TESTSTRING

Value at launch - (null)
Value after adding data - TESTSTRING
Value after deleting data - TESTSTRING

Value at launch - (null)
Value after adding data - TESTSTRING
Value after deleting data - TESTSTRING
Run Code Online (Sandbox Code Playgroud)

例如,它似乎没有更新退出应用程序的价值.

编辑:我在运行iOS 7.1.2的iPad 2上测试了相同的代码; 它似乎每次都能正常工作.

TLDR - 在iOS 8中,[NSUserDefaults standardUserDefaults]工作不可靠吗?如果是这样,有一个解决方法/解决方案?

que*_*ish 14

iOS 8引入了许多行为更改NSUserDefaults.虽然NSUserDefaultsAPI变化不大,但行为已经以可能与您的应用程序相关的方式发生了变化.例如,-synchronize不鼓励使用(并且一直都是).对Foundation和CoreFoundation的其他部分(例如文件协调)以及与共享容器相关的更改的添加更改可能会影响您的应用程序和您的使用NSUserDefaults.

NSUserDefaults特别是写作因此而改变了.编写需要更长时间,并且可能有其他进程竞争访问应用程序的用户默认存储.如果您NSUserDefaults在应用程序退出时尝试写入,则在某些情况下提交写入之前,您的应用程序可能会被终止.exit(0)在您的示例中强制终止使用很可能会刺激此行为.通常,当退出应用程序时,系统可以执行清理并等待未完成的文件操作完成 - 当您使用exit()或调试器终止应用程序时,这可能不会发生.

一般来说NSUserDefaults,在iOS 8上正确使用时是可靠的.

这些更改在OS X 10.10Foundation发行说明中进行了描述(目前还没有针对iOS 8的单独的Foundation发行说明).


Igo*_*gor 9

看起来iOS 8不喜欢在NSUserDefaults中设置字符串.在保存之前尝试将字符串编码为NSData.

保存时:

[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:testString] forKey:@"Session"];
Run Code Online (Sandbox Code Playgroud)

阅读时:

NSData *_data = [[NSUserDefaults standardUserDefaults] objectForKey:@"Session"];
NSString *_dataArchive = [NSKeyedUnarchiver unarchiveObjectWithData:_data];
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 我的8个大量使用NSUserDefaults的应用已经停止为很多用户保存数据.所有这些因为保存的变量之一是一个字符串.用上述方法替换后,保存工作正常. (3认同)