Data Protection ON:iOS重启后,standardUserdefaults已损坏

时间:2013-03-16 13:51:37

标签: iphone ios objective-c nsuserdefaults

更新1:当iOS的数据保护(即密码锁定)关闭时,不会发生问题!

更新2:禁用ARC时不会发生问题。

更新3:在重启iOS之前杀死应用程序时不会发生问题。

My Settings类使用+ initialize实现Singleton模式(加上代码以查看发生了什么):

@implementation Settings

static Settings*        sharedSettings;
static NSUserDefaults*  userDefaults;

+ (void)initialize
{
    if ([Settings class] == self)
    {
        sharedSettings = [self new];
        userDefaults = [NSUserDefaults standardUserDefaults];


        // Code to see what's going on here ...
        if (userDefaults == nil)
        {
            [[[UIAlertView alloc] initWithTitle:@"userDefaults == nil"
                                        message:nil
                                       delegate:nil
                              cancelButtonTitle:@"Close"
                              otherButtonTitles:nil] show];
        }
        else
        {
            if ([userDefaults objectForKey:@"Hello"] == nil)
            {
                [[[UIAlertView alloc] initWithTitle:@"Hello == nil"
                                            message:nil
                                           delegate:nil
                                  cancelButtonTitle:@"Close"
                                  otherButtonTitles:nil] show];
            }
            else if ([userDefaults boolForKey:@"Hello"] == NO)
            {
                [[[UIAlertView alloc] initWithTitle:@"Hello == NO"
                                            message:nil
                                           delegate:nil
                                  cancelButtonTitle:@"Close"
                                  otherButtonTitles:nil] show];
            }

            [userDefaults setBool:YES forKey:@"Hello"];
            if ([userDefaults synchronize] == NO)
            {
                [[[UIAlertView alloc] initWithTitle:@"synchronize == NO"
                                            message:nil
                                           delegate:nil
                                  cancelButtonTitle:@"Close"
                                  otherButtonTitles:nil] show];
            }
        }
    }
}

+ (id)allocWithZone:(NSZone*)zone
{
    if (sharedSettings && [Settings class] == self)
    {
        [NSException raise:NSGenericException format:@"Duplicate Settings singleton creation"];
    }

    return [super allocWithZone:zone];
}

+ (Settings*)sharedSettings
{
    return sharedSettings;
}

@end

我在AppDeletate.m中触发此代码(完全剥离):

#import "AppDelegate.h"
#import "Settings.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [Settings        sharedSettings];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window makeKeyAndVisible];

    return YES;
}

@end

现在非常奇怪的是,在重新启动iOS后立即运行这个空应用程序时,我得到“synchronize == NO”和“Hello == nil”弹出窗口。当我杀死应用程序然后再次运行时,一切都很好。 事实证明,当我使用GCD的dispatch_after()延迟userDefaults = [NSUserDefaults standardUserDefaults]和后续语句时,一点点(我做了2秒,但可能会少得多)可能会消失。 有人可以告诉我为什么会这样,或者这是一个简单的角色案例iOS bug还是副作用???

附加:事实​​证明,当我在重启iOS之前杀死应用程序时,这个问题就消失了。这对我来说证明它是iOS中的东西。

感谢收听!

科内利斯

ps:你可以相信我,我完全剥离了我的应用程序,只有三个模块:main.mm(标准XCode生成单行),AppDelegate.m(上面显示的完整代码)和Settings.m(上面显示的完整代码)。所以根本没有其他代码运行。 当我进一步剥离它,只留下AppDelegate.m时,问题仍然存在。

1 个答案:

答案 0 :(得分:2)

+initialize期间,您不应该引用其他类。关于它何时运行以及此时存在的其他类没有任何承诺。 +initialize应该只做内部到课堂的工作。

自添加GCD以来,该单例模式已被取代。您应该出于各种原因使用GCD模式,其中一个原因是当您认为它运行时它会运行。

How do I implement an Objective-C singleton that is compatible with ARC?

作为一个说明,我对你的main.mm感到好奇。制作顶级ObjC ++几乎总是一个坏主意,并可能导致一些令人惊讶的副作用。 (ObjC ++是一种古怪的粘合语言,有很多奇怪的行为。你应该在尽可能少的类中使用它。)我个人会看到将这个更改回.m是否解决了问题,尽管我仍然建议使用GCD -Singleton而不是+initialize