0

この実装のどこが間違っているのか、ロードされたシングルトンがメモリに残るようにするにはどのような調整が必要なのか、よくわかりません。

@implementation ApplicationSettings

static ApplicationSettings *sharedSettings = nil;

+ (void)load
{
    @autoreleasepool {
        sharedSettings = [self sharedSettings];
        [self configureInitialSettings];
    }
}

+ (ApplicationSettings*) sharedSettings {
    if (sharedSettings)
        return sharedSettings;
    else {
        return [[[ApplicationSettings alloc] init] autorelease];
    }
}

- (void) dealloc {
    [super dealloc];
}

読み込みの主な方法を、dealloc とともにここに示します (私は ARC を使用していません)。

最近このパターンを使い始めました。各実装をチェックして、それが正しいことを確認する必要があります。割り当てが解除されてクラッシュするケースが 1 つ見つかりました。明らかに @autoreleasepool がそれを所有しています。autorelease プールに入らないように、return ステートメントで autorelease を削除する必要がありますか? 私がそれを行うと、プログラムが強制終了されるまで保持されます。これは私にとっては問題ありません。それは何か問題がありますか?

4

1 に答える 1

1

これは、シングルトン クラスを宣言する正しい方法ではありません。(その結果、+loadメソッドとオブジェクトの保持がここでの使用法とクラッシュの理由に適合しません)

  • メソッドにシングルトン インスタンスをロードして+loadも意味がありません。必要なとき、つまり最初に要求されたとき (遅延ロード) にのみインスタンスを割り当てるのが最善であるためです。
  • しかし、もっと重要なのは、sharedSettingsメソッドで自動解放されたインスタンスを返すと、シングルトン パターンが無効になり、その目的に失敗することです。これは、自動解放プールが空になるとすぐに解放されるインスタンスを返すためです (つまり、現在の RunLoop 反復の最後です)。 -- インナーを使用されている場合はお早めに@autoreleasepool)。それがあなたのクラッシュの原因である可能性が非常に高いです!
  • の実装deallocは役に立ちません。まず、その実装を呼び出すだけなsuperので (メソッド定義全体を避けることができます)、クラスがシングルトンであることを意図しているため、アプリが生きている間はインスタンスがメモリから解放されることはありません。
  • 最後になりましたが、実装はまったくスレッドセーフではありません。

もちろん、通常はバランスを取り、またはコールでコールする必要allocがありinitます。これがメモリ管理の主なルールです。しかし、シングルトン パターンの場合、定義によると、シングルトンの共有インスタンスは、アプリケーションが稼働している限り存続します (これが主な役割です)。これはルールの例外であり、シングルトン オブジェクトを保持する sharedInstance を解放しないでください。それが生き続け、メモリから解放されないようにするためです。releaseautorelease


ARC を使用しないシングルトンの正しい (レガシー) 実装の 1 つは、シングルトンに関する Apple ドキュメントで説明されているように、alloc/ retain/ release/ autorelease/メソッドをオーバーロードすることです。retainCountしかし、実際には、このドキュメントはかなり古く (GCD が存在する前に書かれたもの)、時代遅れであり、 GCD は現在、スレッドセーフであることが保証されているより良い代替手段を提供しているため、最近ではそれを行う方法ではありません。また、非 ARC と ARC の両方とも互換性があります(後者は ARC 環境では実装できません)。だからここに行く:

@implementation ApplicationSettings
+(ApplicationSettings*)sharedInstance
{
    static ApplicationSettings* sharedInstance = nil;
    static dispatch_once_t once;
    dispatch_once(&once, ^{ sharedInstance = [[self alloc] init]; });
    return sharedInstance;
}
@end

それだけです。メソッド外のグローバル変数は必要ありません。このメソッドを宣言し、シングルトンへのアクセスが必要になるたびに使用するだけで完了です。そして、シングルトンのいくつかのインスタンス変数を埋める必要がある場合は、おそらくメソッドで行うように、通常の標準クラスで行うように、シングルトンconfigureInitialSettingsのメソッドで行うだけです。init


追加の注意:本当に厳密にしたい場合は、 alloc/init を使用してクラスの他のインスタンスの割り当て/作成を禁止しないと主張する人もいるかもしれません(また、質問で独自の実装を行うこともありません)。シングルトン: 本当に必要な場合は、複数のインスタンスを割り当てることができます。

しかし、実際には、それが真実であったとしても、これらの制約を実際に追加する理由がわかりません (また、ある日 ARC に切り替えた場合、いずれにせよこれらの制約を追加することはできません)。シングルトン パターンを探すときに本当に必要なのは、「複数のインスタンスの作成を禁止する方法」よりも「アプリケーション全体で共有される共通のインスタンス」であり、それがここにあるものです。実際、シングルトンであると主張するほとんどのクラスがそうです (NSFileManagerたとえば)。

于 2012-09-16T00:14:49.330 に答える