1

更新 1: iOS のデータ保護 (つまり、パスコード ロック) がオフの場合、問題は発生しません!

更新 2: ARC が無効になっている場合、問題は発生しません。

更新 3: iOS を再起動する前にアプリを強制終了しても、問題は発生しません。

私の設定クラスは、 +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 を再起動した直後にこの空のアプリを実行すると、「同期 == NO」と「Hello == nil」の両方のポップアップが表示されることです。その後、アプリを強制終了して再度実行すると、すべて問題ありません。userDefaults = [NSUserDefaults standardUserDefaults] と、GCD の dispatch_after() を使用した後続のステートメントを少し遅らせると (2 秒間実行しましたが、おそらくそれよりも短い時間で十分です)、問題が解決することがわかりました。誰かがこれがなぜなのか、またはこれは単純なコーナーケースの iOS バグまたは副作用なのか教えてもらえますか?

追加: iOS を再起動する前にアプリを強制終了すると、この問題は解決することがわかりました。これは私にとって、それがiOSの何かであることを証明しています。

聞いてくれてありがとう!

コーネリス

ps: 信じてください。アプリを完全に削除しました。モジュールは 3 つだけです: main.mm (標準の XCode によって生成されたワンライナー)、AppDelegate.m (上記の完全なコード)、および Settings.m (完全なコードが表示されています)その上)。したがって、他のコードはまったく実行されていません。AppDelegate.m だけを残してさらに削除すると、問題は残りました。

4

1 に答える 1

2

の間に他のクラスを参照しないでください+initialize。それがいつ実行され、その時点で他にどのようなクラスが存在するかについての約束はありません。+initializeクラス内の作業のみを行う必要があります。

このシングルトンパターンは、GCDの追加以降に取って代わられました。GCDパターンはさまざまな理由で使用する必要がありますが、その1つは、実行されていると思ったときに実行されることです。

ARCと互換性のあるObjective-Cシングルトンを実装するにはどうすればよいですか?

注意として、私はあなたについて興味がありますmain.mm。トップレベルのObjC++を作成することは、ほとんどの場合悪い考えであり、いくつかの驚くべき副作用につながる可能性があります。(ObjC ++は、多くの奇妙な振る舞いをする奇抜なグルー言語です。できるだけ少ないクラスで使用する必要があります。).m問題を解決するためにこれを元に戻すかどうかを個人的に確認しますが、使用するよりもGCD-Singletonをお勧めします。+initialize

于 2013-03-16T14:03:14.613 に答える