1

こんにちは、スタンフォードの iOS 開発クラスに取り組んでいます。スレッドについて質問があります。UIKit の呼び出しはメイン スレッドで処理する必要があることを理解しています。このようなものが合法かどうか疑問に思っていましたか?

- (UIImage *)mapViewController:(MapViewController *)sender imageForAnnotation:(id<MKAnnotation>)annotation {
    FlickrPhotoAnnotation *fpa = (FlickrPhotoAnnotation *) annotation;
    NSURL *url = [FlickrFetcher urlForPhoto:fpa.photo format:FlickrPhotoFormatSquare];

    __block UIImage *image;
    dispatch_queue_t downloadQ = dispatch_queue_create("download queue", NULL);
    dispatch_async(downloadQ, ^{
        NSData *data = [NSData dataWithContentsOfURL:url];
        if (data) {
            dispatch_async(dispatch_get_main_queue(), ^{
                image = [UIImage imageWithData:data];
            });
        }
    });
    dispatch_release(downloadQ);
    return image;
}

または、NSData を返して、呼び出し元のメソッドですべてのスレッドを処理する必要がありますか?

ありがとう

4

2 に答える 2

2

あなたのコードはあなたが望むことをしません。

非同期ブロックをキューに入れ、すぐにメソッドから戻ります。戻る前にブロックが実際に実行されるという保証はありません。実際、実行されない可能性があります。

したがって、 の現在の値を返しますimage。初期化していないので、おそらくゴミです。このメソッドを呼び出す人は誰でも、画像へのガベージ ポインターを使用しようとし、(運が良ければ) クラッシュします。nil に初期化した場合:

__block UIImage *image = nil;

それはもう少し礼儀正しいでしょう。

ここでの問題は、メソッドが a を返さなければならないため、返される前にUIImage完全に構​​築された a を作成するのにかかる時間を待たなければならないことです。UIImage他のスレッドでこれを実行しても何のメリットもありません。同じ時間待機しているため、スレッドを切り替えるとオーバーヘッドが増えるだけです。

便利な非同期方法で画像を読み込むには、デリゲート メソッドまたはブロックへのコールバックを介して、画像の読み込みが完了したことを呼び出し元に非同期で伝える何らかの方法が必要です。たとえばNSURLConnection、Foundation を見てください。デリゲートを介してコールバックする古いメソッドと+sendAsynchronousRequest:queue:completionHandler:、ブロックを介してコールバックする新しいメソッド ( ) があります。

于 2012-04-09T05:22:27.333 に答える
0

CodaFi のコメントに同意します。実際、イメージはメイン スレッドから作成できます。UIView の作成と操作はメイン スレッドで行う必要がありますが、UIImage は UIView ではありません。さらに、別のスレッドで表示されている UI を操作しようとすると、ランタイムが警告またはエラーを表示する可能性があります (別のスレッドで UITableView を誤って更新したときに発生しました)。

于 2012-04-09T04:43:12.090 に答える