0

私のような状況で非同期ブロックを使用する際のベスト プラクティスについて質問があります。

たとえば、2 つのコントローラーがあります (コントローラー 1 とコントローラー 2 とします)。

controller1 内に controller2 をプッシュしています。

controller2 * c = [[controller2 alloc] init];
[self.navigationController pushViewController:c animated:YES];
[c release];

controller2 にはインスタンス変数があります。

@interface controller2 : UITableViewController{
    UIImageView * imageView;
}

それを割り当てて解放します。

- (id)init{
   ...
   imageView = [[UIImageView alloc] init];
   ...
}

- (void)dealloc{
   [imageView release];
   [super dealloc];
}

controller2 は、この imageView のイメージをダウンロードします。

- (void)viewDidLoad{
 ...

[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:
    ^(NSURLResponse *response, NSData *data, NSError *error) {
        UIImage * image = [[UIImage alloc] initWithData:data scale:[[UIScreen mainScreen] scale]];
        imageView.image = image; 
        [image release];    
    }];
 }

明らかに、ユーザーはナビゲーション バーの上部にある [戻る] ボタンを押すことができ、controller2 のオブジェクトはこの imageView で解放されます。

状況:

  • ダウンロードが開始されます。

  • コントローラーがポップされました (ユーザーが「戻る」ボタンを押しました)

  • ダウンロード終了、imageView.image=画像が原因(?) EXC_BAD_ACCESS(imageViewが解放されているため)

では、コードでクールにするにはどうすればよいでしょうか? ブロック好き!NSURLConnection デリゲートと比較して、非常に楽しく、少ないコード/クラスです。

  • ブロックはおそらくインスタンス変数を保持していますか? ( :OOO )

  • ブロックの前にインスタンス変数を保持し、ブロックで解放する必要がありますか? (それはばかげていると思います)

では、そのようなブロックを使用する際のベストプラクティスは何ですか? コードを改善するために、このような状況でブロックを使用しないでください。

ps: 私はこれをしようとしました: NSOperationQueue をインスタンス変数として作成し、dealloc のすべてのタスクを停止します..しかし、それはこのブロックの利点を殺します:(その場合、デリゲートで私のダウンローダークラスを使用する方が良いです;(とにかく多すぎるコード。

pps: コントローラーをポップしたらダウンロードを停止する必要があることはわかっています。しかし、私はそれについてではありません。ユーザーがこのコントローラーを離れたとしても、何らかのタスク (たとえば、ビデオの変換など、「重い」バックグラウンド スレッド) を実行する必要がありますが、インスタンス変数が有効な場合はいくつかのインスタンス変数を使用します。

ありがとうございました

4

3 に答える 3

1

次のように変数を宣言する必要があります。

    __block UIImageView*imageView;
于 2012-10-13T19:54:03.473 に答える
0

あなたのブロックアプローチは良いと思います。私はあなたを取得しているのはメモリ管理だと思います:なぜcontroller2はそのdeallocメソッドでimageViewをdeallocするのですか?それは

[imageView release];

デアロックではありません。controller2はそのimageViewを保持しますか?

これが機能する理由は、NSURLConnectionブロックがimageViewをキャプチャしようとしているため、controller2がなくなった後でもハングしているためです。押し戻すと、コントローラーが消え、imageViewが新しい画像を取得してから、それも消えます。すべてがうまくいくはずです。

私はあなたに同意します、ブロックは素晴らしいです。もう1つの素晴らしい点はARCであり、この2つはうまく調和しています。このプロジェクトでARCを使用できますか?

于 2012-10-13T19:45:41.933 に答える
0
[NSURLConnection sendAsynchronousRequest:request queue:imageDownloadersQueue completionHandler:^(NSURLResponse *response, NSData *firstImageData, NSError *error) {
        NSLog(@"first block beginning [self retainCount] = %d, [imagesDictionary retainCount] = %d",[self retainCount], [imagesDictionary retainCount]);

        NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
        UIImage * first_image = [[[UIImage alloc] initWithData:firstImageData scale:[[UIScreen mainScreen] scale]] autorelease];
        [NSURLConnection sendAsynchronousRequest:request queue:imageDownloadersQueue completionHandler:^(NSURLResponse *response, NSData *secondImageData, NSError *error) {
            NSLog(@"second block beginning  [self retainCount] = %d, [imagesDictionary retainCount] = %d",[self retainCount], [imagesDictionary retainCount]);
            UIImage * second_image = [[[UIImage alloc] initWithData:secondImageData scale:[[UIScreen mainScreen] scale]] autorelease];
            if(first_image && second_image){
                [imagesDictionary setObject:[NSArray arrayWithObjects:first_image, second_image, nil] forKey:match.match_id];
            }            
        }];
    }];

最初のブロックの始まり [自己保持カウント] = 2、[imagesDictionary保持カウント] = 1

2 番目のブロックの開始 [自己保持カウント] = 2、[imagesDictionary 保持カウント] = 1

ブロックは「自己」を保持し、最後に解放しているように見えるため、ブロックの終了前に「自己」(私のインスタンス) の割り当てを解除することはできません

それが答えですよね?そう願って...

ありがとう

于 2012-10-15T17:40:00.663 に答える