2011-02-10 3 views
5

"に割り当てられたオブジェクトの潜在的なリークnに格納され、 '変数'に格納されている可能性があります。このXcode Clangスタティックアナライザの警告をどのように抑制できますか?

通常、これは非常に有用なアナライザーの警告ですが、アナライザーの結果をきれいに保つために抑制したいと思っている偽陽性の厄介なものがいくつかあります。アナライザの防御では、別の実行パス(それが目に見えない)でのリリースではないことに気づいたことは間違いなくメモリリークになります。

私の状況を詳しく説明します。さまざまな味がありますが、一般的なパターンは次のとおりです。

  1. オブジェクトが割り当てられ、その代理人が設定されています。
  2. 何かがオブジェクトで行われます。 (開始されたタスク、表示されたビューなど)。
  3. 現在のメソッドの実行が終了します。 (Clang警告を入力してください)。
  4. オブジェクトはタスクが完了したことを判断し、代理人にメッセージを送信します。
  5. 委任者オブジェクトを解放します。

これはまったく難解なデザインパターンではないので、私は抑制が可能であると考えています。私はそれが後でリリースされるivarに違反オブジェクトを格納することによって避けることができることを知っていますが、私はivar汚染を追加しないことを大いに好んでいます。

+0

オブジェクトの代理人がそれを保持していると奇妙に感じます。通常、オブジェクトはそのオブジェクトを代理オブジェクトとして保持し、オブジェクトを保持する代理オブジェクトに保持サイクルを持たせるようにします。私は、デリゲートがオブジェクトを(おそらく短命に)保持したいかもしれないゼロのケースがあると言っているわけではありませんが、なぜそれがここに当てはまるのかを知ることは重要です。ここで言われていることから、デリゲートがalloc/initの暗黙の保持を「所有権を取る」よりも、操作の間、オブジェクトとそれ以降のデリゲートメッセージを保持することがより正当なものだと言います。 – ipmcc

+0

@ipmcc:オブジェクトがそのデリゲートを保持することは可能ですが、クラスにはちょっとしたところがありますが、デリゲートを弱い参照として保存するのが一般的ですあなたが言及するサイクルを保持する。いずれにしても、デリゲートを保持するのはオブジェクトにとって「典型的な」ものではありません。私の場合、いくつかのクラスはalloc/initでオブジェクトを作成し、デリゲートとして自身を設定しました。クラスの所有者として、デリゲートは後でオブジェクトが終了したときにそのオブジェクトを解放します。ここには何ら工夫はありません。 –

+0

@ipmcc - マットが正しいです、通常のパターンは:オブジェクトAはオブジェクトBを作成し、それをオブジェクトBのデリゲートとして設定します。オブジェクトAはオブジェクトBを保持します。オブジェクトAが解放されると、オブジェクトBのデリゲートとして自身を設定解除します。そうでなければクラッシュする可能性があります。 – DougW

答えて

6

Clangにはいくつか新しいSource Annotationsがあります。具体的には、ns_consumedという属性に興味があります。

+0

これはちょうど私が探しているようだが、attribute_ns_consumedは利用可能ではないようです。__has_feature(attribute_ns_consumed)はfalseを返します。サイトのドキュメントは、特にMac OS X API Annotationsと呼んでいます。これらはiOSでは利用できませんか? –

+0

命名法は少し誤解を招いています。実際はCocoa API注釈を意味します。そして 'ns_consumed'はむしろ新しいものです。 Clang 1.6にはXcode 3.2が付属しているとは思えませんが、Clang 2.0が(私はテストしていません)願っています。 –

+0

さて、私は2.0、およびサイコロを使用しています。残念です... –

1

この場合、静的アナライザーのメッセージに注意する必要があります。あなたのパターンには潜在的な問題があります。

具体的には、手順5を実行するために呼び出されたメソッドから戻ると、すでに割り当てが解除されている可能性のあるオブジェクトのメソッドに含まれています。

// steps 1, 2, 3 
-(void) methodThatCreatesObject 
{ 
    id theObj = [[TheObj alloc] init]; 
    [theObj setDelegate: delegateObj]; 
    // other stuff 
} 

注上記の違反memory management rules

// step 4 - a method of theObj 
-(void) someMethod 
{ 
    [delegate notifyTaskCompleteFromObj: self]; 
    // self points to an invalid object here. Doing anything with self results in EXC_BAD_ACCESS 
} 

メモリ管理ルールに記載された仮定上の違反:

Aがオブジェクトを受け取ったが、私はこのようなあなたのパターンに何かを解釈します受け取ったメソッド内で有効であることが通常保証される

selfが受信されたオブジェクトであるとすると、これは技術的にはスタック上のパラメータとして渡されるためです。

// step 5 the delegate method defined in the delegate object 

-(void) notifyTaskCompleteFromObj: (TheObj*) anObj 
{ 
    // do stuff 
    [anObj release]; 
} 

上記はまた、メモリ管理ルールに違反します。

通常のパターンは、デリゲートとデリゲートを持つオブジェクトの両方を所有するコントローラを持つことです(多くの場合、コントローラ自体はデリゲートです)。私はあなたがそのパターンに移行すべきだと思います。

+0

それが私のパターンだったら、私はあなたに同意するでしょう。私の一般化はあまりにも多くの解釈の余地を残していたと思う。具体的な例を次に示します。コントローラーオブジェクトのメソッドでは、別のオブジェクト(カスタムネットワーク要求)が割り当てられ、デリゲートは別のオブジェクトではなく自己に設定されます。したがって、コントローラーは代理人として動作しているオブジェクトを所有しています。後で、ネットワーク要求からの通知を受信すると、コントローラは要求を解放する。違反はありません。私は別のオブジェクトに責任を渡すわけではありません。 –

+0

@Matt:私の例の 'theObj'がインスタンス変数だと言っていますか? – JeremyP

+0

いいえ、そうではありません。私はそれを後で解放するためのivarとして参照を保持することができますが、TheObjがデリゲートメッセージの参照を渡すので、解放するためにivarを追加するのではなく、メッセージのパラメータとして渡された参照を解放することにしますそれ。 theObjへの参照の欠如は、アナライザが好きではないものです。 –

0

もう1つの興味深いオプションが私に発生しました。オペレーションは次のシナリオを示しました:

  1. オブジェクトが割り当てられ、その代理人が設定されています。
  2. 何かがオブジェクトで行われます。 (開始されたタスク、表示されたビューなど)。
  3. 現在のメソッドの実行が終了します。 (Clang警告を入力してください)。
  4. オブジェクトはタスクが完了したことを判断し、代理人にメッセージを送信します。
  5. 委任者オブジェクトを解放します。 FOOを設定することにより

    TheObject* foo = [[TheObject alloc] init] autorelease]; 
    foo.delegate = self; 
    [foo doSomething]; 
    objc_setAssociatedObject(self, foo, foo, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
    return; 
    

の場合は、代わりに明示的なリリースの、あなたは単にこれに割り当て/ delegeateオブジェクト、あなたは可能性のそれに割り当てられたオブジェクトの生存期間を延長したいです保持ポリシーを持つ関連オブジェクトであれば、デリゲート(self)はデリゲート(self)が解放されるたびに後で解放されるオブジェクトを保持します(後で)。

OPが尋ねたことはまったく正確ではありませんが、有用なパターンですが、OPが提示した状況ではおそらく十分であるように感じます。

関連する問題