2

アプリケーションのいくつかの場所でシングルトンパターンを使用していますがclang、コードを分析するとメモリリークエラーが発生します。

static MyClass *_sharedMyClass;
+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      [[self alloc] init];
  }
  return _sharedMyClass;
}

// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked)

私はこれらの設定を次の目的で使用していますscan-build

scan-build -v -v -v -V -k xcodebuild

シングルトンのコードは問題ないと確信しています-結局のところ、これはここでスタックオーバーフローとAppleのドキュメントで参照されているコードと同じです-しかし、メモリリークの警告を整理してスキャンしたいのですが-ビルドは成功を返します。

4

5 に答える 5

6

私は非常に密集しているかもしれませんが、確かにあなたのライン5

[[self alloc] init];

含まれているクラスタイプのオブジェクトを割り当て、すぐに破棄しますか?したくない

_sharedMyClass = [[self alloc] init];

于 2009-05-06T16:16:13.157 に答える
5

Apple はその後、推奨されるシングルトン コードを更新して、静的アナライザーを渡しました。

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedManager] retain];
}

+sharedManagerスーパーを呼び出し-allocWithZone:て の戻り値を割り当て、-initシングルトンは保持されたsharedInstance-allocWithZone:を返すだけです。

編集:

+allocWithZone: で保持するのはなぜですか?

+allocWithZone: はオーバーライドされます。これは、MyGizmoClass を使用しているユーザーが、[MyGizmoClass sharedManager] の代わりに [[MyGizmoClass alloc] init] を呼び出すことでシングルトンを回避できるためです。+alloc は常に保持カウントが +1 のオブジェクトを返すことが期待されるため、保持されます。

+alloc へのすべての呼び出しは、-release または -autorelease とバランスを取る必要があるため、+allocWithZone: で保持しないと、共有インスタンスが他のユーザーから割り当て解除される可能性があります。

于 2009-12-08T01:55:27.780 に答える
4

Mike Ash のサイトに投稿された、シンプルでメソッドが 1 つの GCD ベースのシングルトン実装 (したがって 10.6+ のみ) に興味があるかもしれません。

+ (id)sharedFoo
{
    static dispatch_once_t pred;
    static Foo *foo = nil;

    dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
    return foo;
}
于 2009-11-12T22:15:34.843 に答える
1

selfクラス メソッドで参照しています。ビッグノーノー!次に、インスタンスを呼び出し[[self alloc] init]て破棄しています。クラスメソッドでシングルトン参照を割り当てる必要がありinitます。私が推測しているようなものではありません。_sharedMyClass次に、ゼロに初期化されるという実際の保証はありません。に明示的に初期化する必要がありますnil

static MyClass *_sharedMyClass = nil;

+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      _sharedMyClass = [[MyClass alloc] init];
  }
  return _sharedMyClass;
}
于 2012-08-18T04:24:05.407 に答える
0

これも入っていたかも…。

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  // assignment and return on first allocation
        }
    }
    return nil; // on subsequent allocation attempts return nil
}

init に保存しなかった理由は、 alloc が呼び出したメソッドに保存していたためです。これは、Apple が例に示したパターンです。値を init にも保存すると、すべて問題なく警告が消えます。allocWithZone の実装はそのままにしておきます。

于 2009-11-06T03:47:05.583 に答える