5

ネットでそのシングルトンパターンを見つけました。最適化できるものがたくさんあるように思えます。

-sharedMySingletonメソッドでは、retain を呼び出す必要はありませんか? よくわかりません...
-そうでない場合、なぜに保持があるのallocWithZoneですか?
- の用途は何ですか@synchronized。NSAssert は、ブロックが何度も呼び出される可能性があると考えさせます。そのため、そうであれば、前のメモリを解放するためのコードがさらに必要であるか、NSAsserting だけでなく明確にブロックを終了する必要があります。
- と の間のチェーンは奇妙sharedMySingletonalloc思えます。私は自分自身を次のように書いていました:

+(MySingleton*)sharedMySingleton
{
    @synchronized([MySingleton class])
    {
        if (_sharedMySingleton == nil) _sharedMySingleton = [[self alloc] init];
        return _sharedMySingleton;
    }

    return nil;
}

+(id)alloc
{
    @synchronized([MySingleton class])
    {
        return [super alloc];
    }

    return nil;
} 

シングルトン パターン

#import "MySingleton.h"

@implementation MySingleton

// ##########################################################################################################
// ######################################## SINGLETON PART ##################################################
// ##########################################################################################################
static MySingleton* _sharedMySingleton = nil;

// =================================================================================================
+(MySingleton*)sharedMySingleton
// =================================================================================================
{
    @synchronized([MySingleton class])
    {
        if (_sharedMySingleton == nil) [[self alloc] init];
        return _sharedMySingleton;
    }

    return nil;
}

// =================================================================================================
+(id)alloc
// =================================================================================================
{
    @synchronized([MySingleton class])
    {
        NSAssert(_sharedMySingleton == nil, @"Attempted to allocate a second instance of a singleton.");
        _sharedMySingleton = [super alloc];
        return _sharedMySingleton;
    }

    return nil;
} 

+ (id)allocWithZone:(NSZone *)zone  { return [[self sharedMySingleton] retain]; }
- (id)copyWithZone:(NSZone *)zone   { return self; }
- (id)retain                        { return self; }
- (NSUInteger)retainCount           { return NSUIntegerMax;  /* denotes an object that cannot be released */}
- (oneway void)release              { /* do nothing */ }
- (id)autorelease                   { return self; }

// ##########################################################################################################
// ##########################################################################################################
// ##########################################################################################################

// =================================================================================================
-(id)init 
// =================================================================================================
{   
    if (!(self = [super init])) return nil;

    return self;
}

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

// =================================================================================================
-(void)test 
// =================================================================================================
{
    NSLog(@"Hello World!");
}

@end
4

3 に答える 3

17

このパターンはまったく使用しないでください (これは、Singleton の非常に特殊なケースであり、ほとんど必要がなく、その場合でも通常は使用しないでください)。

What should my Objective-C singleton look like?で議論されている多くの良いパターンがあります。、しかしそれらのほとんどはGCDのリリース以来時代遅れです. 最新バージョンの Mac および iOS では、リンクされた質問で Colin Barrett が提供する次のパターンを使用する必要があります。

+ (MyFoo *)sharedFoo
{
    static dispatch_once_t once;
    static MyFoo *sharedFoo;
    dispatch_once(&once, ^{ sharedFoo = [[self alloc] init]; });
    return sharedFoo;
}

古い質問の最高評価の回答は古くなっているため、質問を重複としてマークするのではなく、ここにコピーするだけです。

于 2012-04-08T20:52:26.333 に答える
0

sharedMySingleton メソッドでは、retain を呼び出す必要はありませんか?

alloc参照カウントが 1 の新しいインスタンスを返すため、保持は必要ありません。

そうでない場合、allocWithZone に保持があるのはなぜですか?

ルールによれば、 を呼び出すallocWithZoneと参照を所有するためallocWithZone、参照カウントが大幅に増加します。しかし、この allocWithZone の実装は、他の誰か (sharedMySingletonメソッド) によって既に作成および所有されているシングルトン インスタンスを返しています。したがって、sharedMySingletonメソッドは でオブジェクトを作成するallocため、所有者になります。そして、 を通じて同じインスタンスを取得するため、同じインスタンスallocWithZoneの 2 番目の所有者になります。所有者が 2 人になったので、保持数を増やす必要があります。だからこそallocWithZone、保持する必要があります。

@synchronized の用途は何ですか?

@synchronizedコードを複数のスレッドから同時に呼び出すことができます。sharedMySingleton複数のスレッドから呼び出すことがない場合は、不要であり、省略できます。

NSAssert は、ブロックが何度も呼び出される可能性があると考えさせます。そのため、そうであれば、前のメモリを解放するためのコードがさらに必要であるか、NSAsserting だけでなく明確にブロックを終了する必要があります。

クラスはシングルトンであることを意図しているため、alloc一度だけ呼び出す必要があります。が複数回呼び出された場合、 はプログラムNSAssert()を終了します。はプログラムを終了するallocので、2 回目に呼び出されると、メモリ管理は必要ありません。NSAssert()alloc

于 2012-04-08T21:07:16.043 に答える
0

retainがあるので電話する必要はありませんallocretainその上で呼び出すと、メモリ リークが発生します。これはシングルトンであるため、 retain on がallocWithZoneあるため、クラスの 2 つの異なるインスタンスを作成したくありません。新しいインスタンスを割り当てる代わりに、シングルトン インスタンスの保持数を増やします。何故ですか?おそらく、誰かがクラスのシングルトン タイプを認識していないのを防ぐためです。彼がインスタンスを呼び出しallocWithZoneて解放すると、すべてが正常に機能し、共有シングルトン インスタンスに実際にアクセスしました。

@synchronized2 つの異なるスレッドからの 2 つの呼び出しが同時に if ステートメントに入るのを防ぐために使用されます。したがって、コードはスレッドセーフです。

シングルトンの 2 つのインスタンスが作成された場合、NSSAssert はおそらくアプリを「クラッシュ」させます。これは「念のため」のコードであり、防御的プログラミングとも呼ばれます。

との間のチェーンについては、問題ないsharedMySingletonalloc思います。

于 2012-04-08T21:00:33.067 に答える