6

時々クラッシュするメソッドがあります。

-(void)foo{
    [self doSomething];
    [self.delegate didFinish];
    [self doSomethingElse];
}

-doSomething が正しく機能したら、デリゲート -didFinish を呼び出します。-didFinish 内で、このオブジェクトへの参照が nil に設定され、ARC で解放される場合があります。メソッドがクラッシュすると、-doSomethingElse でクラッシュします。私の仮定は、メソッド内で self が強力であり、関数が完了することを可能にするというものでした。自分は弱いか強いか?これに関するドキュメントはありますか?それが強いか弱いかの理由は何でしょうか?

編集

以下の回答のいくつかに触発されて、私はいくつかの調査を行いました。私の場合のクラッシュの実際の原因は、NSNotificationCenter がオブザーバーを保持していないことです。Mike Weller は、上記のケースを防ぐために、メソッドの呼び出し元が呼び出し中のオブジェクトを保持する必要があることを以下に示していますが、NSNotificationCenter はこの問題を無視し、オブザーバーへの弱い参照を常に維持しているようです。言い換えると:

-(void)setupNotification{
    //observer is weakly referenced when added to NSNotificationCenter
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotification:)
                                                 name:SomeNotification object:nil];
}

//handle the notification
-(void)handleNotification:(id)notification{
    //owner has reference so this is fine
    [self doSomething];
    //call back to the owner/delegate, owner sets reference to nil
    [self.delegate didFinish];
    //object has been dealloc'ed, crash
    [self doSomethingElse];
}
4

2 に答える 2

9

self はメソッド内で強力になり、関数を完了することができます。自分は弱いか強いか?

selfARCでは強くも弱くもありません。呼び出し元が参照を保持していると想定され、self安全でない unretainedです。

ARC の下で独自のメソッド内で edselfできることも事実であり、プログラムがこれを行うことは「未定義の動作 (または少なくとも危険)」と見なされます。-dealloc

それが強いか弱いかの理由は何でしょうか?

パフォーマンスのために保持されていません-(ほとんどの場合)不必要な参照カウントの増減を避けるためです。これらの余分な参照カウント操作をすべて実行したとしても、マルチスレッド プログラムまたは競合状態 (UB) が存在する場合、プログラムは依然としてこのような問題の影響を受けやすくなります。したがって、これは、彼らが (正当に) 防御する必要がないと判断した極端なエッジ ケースの 1 つです。

これに関するドキュメントはありますか?

もちろん!:)

于 2013-08-02T07:52:24.377 に答える
5

self弱くも強くもない。アクセスできる場合selfは、メソッド呼び出しのスコープ内にあり、そのメソッド呼び出しは、所有する必要がある参照を介して誰かによって実行されています。selfスコープ内にある限り有効な参照であることが暗示され、メモリ管理または所有権は呼び出し元によって処理されることが暗示されます。

弱い参照を介してメソッドを呼び出す場合、ARC はそのメソッド呼び出しの間、オブジェクトを保持します (この回答を参照してください)。厳密なコンパイラ警告を有効にすると、その参照にメソッドを送信する前に、実際には強い参照を作成する必要があります。

したがって、定義上、オブジェクトに対してメソッドが呼び出される場合、呼び出し元は既に所有権を持っている必要があり、何もする必要はありません。

もちろん、割り当て解除されたオブジェクトでメソッドを呼び出すことは可能ですが、それは不適切な呼び出し元コードの結果です。

于 2013-08-01T14:29:40.033 に答える