4

私はデリゲートパターンに精通していて、特にビューコントローラが消えるときに進行中の非同期呼び出しを行うときには、私はデリゲートをnilし、コールバックは正常にnilオブジェクトに戻ります。完成ブロックからゾンビから自分のコードを保護する

私は現在、コードを少し読みやすくするために補完ブロックを使って実験しています。

私のビューコントローラからネットワークサービスを呼び出し、私のUITableViewを更新するブロックを渡します。通常の状況下では正常に動作します。ただし、完了する前にビューを終了すると、完了ハンドラブロックが実行されますが、UITableViewは現在ゾンビになっています。

これを処理する通常のパターンは何ですか?

コードサンプルWITH UPDATE

これは私が分割ビューのように、一度に画面上の2つのビューコントローラを持って、iPadアプリです。 1つはディテールであり、もう1つは画像のグリッドです。私はイメージをクリックし、詳細をロードして情報をロードします。しかし、私が画像をクリックすると、あまりにも早く、ネットワーク通話をする機会があります。問題があります。画像を変更すると、画像のお気に入りを数える以下のコードが呼び出されます。

これは私のジレンマです。以下のコードを使用すると、これはうまくいきます。ネットワークが応答します。

__blockを削除して自己に渡すと、ゾンビでクラッシュします。

私は勝てません...私はブロックを使用することについて何か基本的なものが欠けていると確信しています。

__block UITableView *theTable = [self.table retain]; 
__block IndexedDictionary *tableData = [self.descriptionKeyValues retain]; 
FavouritesController *favourites = [Container controllerWithClass:FavouritesController.class]; 
[favourites countFavouritesForPhoto:self.photo 
         completion:^(int favesCount) { 

          [tableData insertObject:[NSString stringWithFormat:@"%i", favesCount] 
               forKey:@"Favourites:" atIndex:1];     
          [theTable reloadData]; 

          [tableData release]; 
          [theTable release]; 
         }]; 

ヒントはありますか?おかげ

SECOND UPDATE

は、私はお気に入りをロードする方法を変更しました。お気に入りがシングルトンである代わりに、私は各写真の変更時にインスタンスを作成します。

[self.favourites countFavouritesForPhoto:self.photo 
         completion:^(int favesCount) {  
          [self.descriptionKeyValues insertObject:[NSString stringWithFormat:@"%i", favesCount] 
               forKey:@"Favourites:" atIndex:1];     
          [self.table reloadData]; 
         }]; 

それは:ブロックは、コールバックにどこにもありません(私はそれも存在していないと思います)と私のコードは今すぐ下のように見え、それが動作しているように見える - これを交換し、古いものを殺すことにより、漏れはなく、クラッシュしているようにも見えません。

+0

'retain' +' release'?しかし、私はそれが完了ブロックが実行されることが保証されているのか分からない – Nekto

+0

このインスタンスでは、私はあなたが正しいと思います。私はブロックプログラミングガイドに戻り、 "__blockストレージタイプ修飾子でマークされたオブジェクト変数は残っていません"という....を再読み込みしていました。しかし、これは私のView Controllerがまだそこにあったからです...もしそうでなければどうしますか?それとも、生き続けるブロックのためにいつもそこにいるのだろうか?ああ脳の痛み... – bandejapaisa

+2

+1「ゾンビから自分のコードを保護する」;-) –

答えて

0

ブロックの先頭でtableviewがnilでないことをテストすることをお勧めします。親ビューが画面外になったときにtableviewが正しく破棄されたように見えるので、その時点以降はテーブルビュー操作は有効ではありません。

ブロック内でUITableViewを保持することは悪い考えです。datasource/tableviewの更新によって暗黙のメソッド呼び出しが発生し、tableviewが画面上に表示されない場合には関係のない通知が発生する可能性があるからです。

+0

ビューコントローラをナビゲーションスタックにプッシュした場合、私のテーブルビューはゼロにならないでしょう。これをもう少しテストするために別のサンプルプロジェクトを一緒に投げます。ありがとうございました – bandejapaisa

0

ブロックには、__blockと注釈されたものを除き、参照するオブジェクトはすべて保持されます。完了ブロックをまったく実行しない場合は、isCancelledのようなプロパティをいくつか作成し、完了ブロックを呼び出す前にYESであるかどうかを確認してください。

+0

うわー、私は__block varsの保持についてそれを読んでいます。 isCancelledはおもしろいパターンのようですが、BOOLが投げ込まれているのを見ても、いつもそれは私に悪い匂いがします。 – bandejapaisa

+0

これはCocoaのNSOperationによって使用されるので、悪くないと思います。あなたの仕事は異なる州を持つことができます。遅延、キャンセル、進行中など。維持するかどうかはあなた次第です。 –

+0

私は一見を持っています、多分それは本当に私が行かなければならない方法です。ありがとう – bandejapaisa

0

他のオブジェクトが終了してその間にオブジェクトが破棄されるバックグラウンド操作があります。記述したクラッシュは、保持されていない参照があるときに発生します。表示される問題は、参照されたオブジェクトがなくなり、ポインタが無効であることです。通常、deallocメソッド内でデリゲートを登録解除して、バックグラウンドタスクを続行し、結果を返信する準備ができたら "シュート、コールバックオブジェクトはnil"と表示され、少なくともそれは ' tクラッシュ。

まだ、弱い参照を手動で処理するのは面倒でエラーが発生しやすいです。 deallocメソッドの中でデリゲートをゼロにするのを忘れることができます。コードがクラッシュする状況が発生する前に、何ヶ月も予告なく変更されることがあります。

iOS 5.0をターゲットにしている場合は、ARCとそれが提供する弱い参照で読んでいます。 ARCを使用したくない場合、または5.x以前のデバイスをターゲットにする必要がある場合は、3.xデバイスでも機能するMAZeroingWeakRefなどの弱参照ライブラリを使用することをお勧めします。

ARCの弱い参照またはMAZeroingWeakRefのいずれかを使用して、これらのファンシーな弱い参照オブジェクトの1つを使用してバックグラウンドタスクを実装します。今度は、指し示されたオブジェクトが消えた場合、弱いポインタはそれ自身がなくなり、あなたのバックグラウンドタスクはクラッシュしません。

+0

返信いただきありがとうございますが、あなたは少し話題になりました。私はこれに新しいことではない。私はデリゲートの使い方を知っており、私はARCを使用していません。私の質問は、非同期ブロック補完ハンドラを持つパターンに関するものです。しかし、あなたの答えに関して - 私は、遅すぎるかもしれないdeallocメソッドではなく、viewWillDisappear内の私の代理人を任命しません - あなたは遅い接続であなたのアプリケーションを使用するか、ネットワークオプティマイザを使ってシミュレータネットワークを減速させ、数ヶ月ではなく数秒で潜在デリゲートコールバックを公開することができます。 – bandejapaisa

+0

あなたは "これを処理するための通常のパターンは何ですか?"と尋ねました。私は答えました:コールバックをゼロにするか弱参照をゼロにするかのどちらかです。 offtopicとは何ですか?これは、非同期ブロック補完ハンドラを処理するための私の現在のプログラミングパターンです。また、viewWillDisappearでnilを指定しても早すぎると、その間にモーダルビューコントローラを表示している間にタスクが終了するとコールバックを受け取らないためです。 –

+0

話題は間違ったフレーズだったかもしれませんが、私が知っていると言ったデリゲートパターンを引用しました。私の経験から、deallocでデリゲートを呼び出すのは遅すぎました。私はそれがユースケースに依存すると思うが、モーダルviewWillDisappearはあまりにも早く音を出す。弱いポインタ情報をありがとう。 – bandejapaisa

関連する問題