8

「MyClass」から継承する 2 つの子クラスがあり、各子クラスはシングルトンにする必要があります。

継承する他のクラスがない場合、静的インスタンスを取得するためにこのパターンを使用しました。

+ (MyClass *)getInstance
{
    static dispatch_once_t once;
    static MyClass *instance;

    dispatch_once(&once, ^{
        instance = [[MyClass alloc] init];
    });

    return instance;
}

これはうまく機能します。ここで、2 つの新しい子クラス (FirstClass と SecondClass) を追加した場合、どちらも MyClass から継承されます。それぞれの ChildClass を確実に取得するにはどうすればよいでしょうか?

dispatch_once(&once, ^{
    // No longer referencing 'MyClass' and instead the correct instance type
    instance = [[[self class] alloc] init];
});

FirstClass *firstClass = [FirstClass getInstance]; // should be of FirstClass type
SecondClass *secondClass = [SecondClass getInstance]; // should be of SecondClass type

上記を実行すると、1 番目にインスタンス化したクラスが 2 番目のクラス型として常に返されます。

first: <FirstClass: 0x884b720>
second: <FirstClass: 0x884b720>
// Note that the address and type as identical for both.

getInstance各子クラスにメソッドを追加せずに、それぞれの子クラスのシングルトンを作成する最良の方法は何ですか?

4

3 に答える 3

6

正当な理由がない限り、通常、シングルトンのサブクラス化は避けるべきです。それは非常に混乱した状況を作り出します。シングルトンを作成する場合、シングルトンを作成MyClassできますFirstClassか? FirstClass常にどこでも使用可能でなければならないのでMyClass(Liskov による)、現在 3 つの「シングルトン」MyClassオブジェクトがあります。現在、ObjC はシングルトンに対して非常にルーズです。これは良いことですが、それでも非常に奇妙です。

OK、そうは言っても、あなたの問題はどうですか?最初に解決策、次に答え。解決策は、MyClass上記で説明したように、おそらくシングルトンであってはならないということです。スーパークラスを取り除きgetInstance、サブクラスで定義するだけです。

何が起こっているかに対する答えはあなたの中にありますdispatch_onceonceすべてのケースで同じ静的トークンを渡しています。特定のトークンに対して一度しかdispatch_once実行されません。これを回避する唯一の方法は、クラスごとに異なるトークンを渡すことですが、各ファイルで dispatch_once コードを複製せずにそれを行う便利な方法を知りません。サブクラスごとに異なるトークンを作成することもできますが、メソッドを複製するだけでは問題が発生し、コードが複雑になる可能性があります。oncesharedInstance

ところで、それを呼び出さないでくださいgetInstance。「get」は ObjC では特別な意味を持ちますが、ここではその意味ではないため、混乱します。これは通常、「何か」がクラスである場合sharedInstance、またはより適切に呼ばれます。が存在する必要があり、 が存在し、 が存在する必要sharedSomethingがあることを本当に意味する場合は、3つすべてに実装できます。MyClassFirstClassSecondClasssharedInstance

于 2012-09-28T02:08:20.937 に答える
1

シングルトンが危険なことを知っていますよね?多くのシングルトンはより大きな問題です。警戒終了。


dispatch_once基本シングルトンを作成するために使用できます。次に、ベースはその派生型のマップ (例: 辞書{キー:クラス名|値:インスタンス}) を保持できます。

あなたが使用していることdispatch_onceは、これがマルチスレッドのコンテキストで使用されることを示唆しています。その場合、ミューテックスを使用して辞書とのやり取りを保護する必要があります。

サブクラスからのメッセージは、メッセージング クラス ( ) に基づいて、selfルックアップするクラスを決定します (必要に応じてそのインスタンスを作成します)。

于 2012-09-27T23:46:11.820 に答える
-1

このようにfirstClassで使用idしますmyClass

+(instancetype)sharedInstance 
{
    static id sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[[self class] alloc] init];
    });
    return sharedInstance;
}

私はこれがうまくいくはずだと思う

于 2015-06-08T08:01:34.083 に答える