3

私は数週間前にobjective-cとiOSを開始しました(覚えておく価値があります)、そしてひどい図を前もってお詫びします!!

ここに画像の説明を入力してください

上の図は、Webサービスへの呼び出しの構造を示しています。細い矢印は、別のオブジェクトを作成するオブジェクトを示し、太い矢印は、ポイントされたオブジェクトへの強い(保持された)参照を保持しているオブジェクトを示します。

これにはいわゆる「循環参照」が含まれており、オブジェクトの割り当てを解除する際に問題が発生すると思います。

私のプロジェクトがiOS3.2もターゲットにしていることを除いて、簡単な答えは弱いものへの強い参照のいくつかを置き換えることであることを理解しています(私の決定ではありません-この事実を実際に変更することはできません!) 。したがって、代わりに__unsafe_unretainedを使用する必要があると言っているのは正しいと思いますが、オブジェクトの割り当てが解除されるとEXC_BAD_ACCESSの問題が発生するため、これらが自動ゼロ化されないという事実についてはかなり心配しています。 ..

したがって、私の問題は、最初に循環参照があることです。解決するには、__ unsafe_unretainedを使用する必要があります。これは、2番目の問題につながります。これらを正しく管理するにはどうすればよいですか。

関連する可能性のある質問は次のとおりです。NSURLConnectionはその強力な参照をどのように管理しますか?さまざまな情報源から、代理人を保持していると聞いたことがありますか?したがって...NSURLConnectionを保持し(そしてそのデリゲートでもあり)、それが私を保持している場合、これも循環参照になりますね?それは私の問題をどのように回避しますか?

どんなアドバイスも大歓迎です!

よろしく、ニック

4

2 に答える 2

6

親が子オブジェクトへの参照を持つ場合、強い参照を使用する必要があります。子がその親オブジェクトへの参照を持っている場合、弱い参照、別名 unsafe_unretained を使用する必要があります。

慣例により、iOS のデリゲート リレーションシップは通常弱い参照であるため、Apple 独自のクラスのほとんどのデリゲート プロパティは unsafe_unretained として宣言されていることがわかります。

したがって、コントローラーは使用しているサービスを保持しますが、サービスはコントローラーに弱くリンクするだけです。そうすれば、コントローラーが解放された場合、循環参照なしでロット全体を安全に破棄できます。

これの危険性は、Web サービスが実行時間の長いタスクを実行していて、コントローラーが完了する前に解放された場合、割り当てが解除されたデリゲートへのダングリング ポインターがサービスに残されることです。「終了しました」などのメッセージをデリゲートに送信しようとすると、クラッシュします。

これを解決するのに役立ついくつかのアプローチがあります (これらは相互に排他的ではありません - 可能な限りすべてを実行するようにしてください)。

1) コントローラーの dealloc メソッドで、サービスのデリゲート プロパティを常に nil に設定します。これにより、コントローラーが解放されたときに、コントローラーへのデリゲート参照が nil に設定されます (ARC の弱い参照が自動的に行うのと同じような大雑把で手動の同等物)。

2) デリゲートを持つ独自のサービス クラスを作成する場合は、実行中はデリゲートを保持し、完了したらデリゲートを解放します。そうすれば、サービスがまだメッセージを送信している間はデリゲート オブジェクトの割り当てを解除できませんが、サービスが終了すると解放されます (NSTimer と NSURLConnections は両方ともこのように機能します。実行中にデリゲートを保持し、解放します)。それらが完了したとき)。

3) ビュー コントローラーのような一時的なものによって長時間実行されるサービスを所有しないようにしてください。サービスを所有するシングルトン オブジェクト (共有静的オブジェクト インスタンス) を作成することを検討してください。これにより、ビュー レイヤーで何が起こっているかに関係なく、サービスがバックグラウンドでジョブを実行できます。コントローラーは引き続きサービスを呼び出すことができますが、それを所有していません。サービスは、アプリが実行されている間存在する静的オブジェクトによって所有されているため、リークや早期リリースのリスクはありません。サービスは、デリゲート呼び出しの代わりに NSNotifications を介してコントローラーと通信できるため、消える可能性のあるオブジェクトへの参照を持つ必要はありません。NSNotifications は、循環参照を作成せずに複数のクラス間で通信する優れた方法です。

于 2012-01-30T14:08:44.920 に答える
1

あなたの質問と懸念はすべて正しいです。assign(現在はより適切な名前の__unsafe_unretained) の以前の使用に関するこの問題が、Apple が の自動ゼロ調整を開発した理由ですweak。しかし、私たちは何年もの間デリゲートをかなり安全に扱ってきたassignので、ご想像のとおり、それを行う方法があります。

まず、練習問題として、デリゲートされたオブジェクトをリリースするときは、常にデリゲートとして自分自身をクリアする必要があります。ARC以前は、これは伝統的に以下で行われていましたdealloc:

- (void)dealloc {
  [tableView_ setDelegate:nil];
  [tableView_ release];
  tableView_ = nil;
}

setDelegate:nilそれをdeallocif delegateisに含める必要があります__unsafe_unretained。これにより、最も一般的な形式の問題 (デリゲート オブジェクトの前にデリゲートの割り当てが解除された場合) に対処できます。

に関してNSURLConnectionは、デリゲートを保持していることも正しいです。通常、デリゲートよりも寿命がはるかに短いため、これは問題ありません (ほとんどの場合、テーブル ビューと同じ寿命を持つテーブル ビュー デリゲートとは対照的です)。ARC以前のコンテキストでのこれに関する詳細な議論については、「委任EXC_BAD_ACCESSエラーを回避/処理する方法は? Obj C 」を参照してください(強い/弱い新しい世界でも同じ概念が適用されます)。

于 2012-01-30T14:23:34.773 に答える