16

私はGCDとブロックが初めてで、それに慣れています。

背景: ALAssetsLibrary を使用して、UIScrollView の遅延読み込みルーチンに取り組んでいます。UIScrollView が読み込まれるとaspectRatioThumbnails、ALAsset が読み込まれ、ユーザーがスクロールすると、以下のルーチンを呼び出して、fullScreenImage現在表示されている ALAsset を読み込みます。うまくいくようです。

(誰かがより良い遅延読み込みルーチンを持っている場合は、コメントを投稿してください。私が見つけることができるすべてとWWDCビデオを見てきましたが、それらはタイリングをより多く扱っているか、必要以上に複雑であるようです)

私の質問:バックグラウンド スレッドを使用してロードを処理しfullScreenImage、それが完了したら、メイン スレッドを使用して UIImageView に適用します。メインスレッドを使用する必要がありますか? すべての UIKit の更新はメイン スレッドで行う必要があることを確認しましたが、それが UIImageView に適用されるかどうかはわかりません。画面要素なのであると思っていたのですが、知らなかったことに気づきました。

- (void)loadFullSizeImageByIndex:(int)index
{
    int arrayIndex = index;
    int tagNumber = index+1;
    ALAsset *asset = [self.assetsArray objectAtIndex:arrayIndex];

    __weak typeof(self) weakSelf = self;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        UIImage *tmpImage = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];

        if ([weakSelf.scrollView viewWithTag:tagNumber] != nil){

            dispatch_async(dispatch_get_main_queue(), ^{

                if ([weakSelf.scrollView viewWithTag:tagNumber]!= nil){
                    UIImageView * tmpImageView = (UIImageView*)[weakSelf.scrollView viewWithTag:tagNumber];
                    tmpImageView.image = tmpImage;
                }
            });
        }
    });
}
4

4 に答える 4

33

UIImageViewはい、やその他の UIKit クラスに触れるときはいつでもメイン スレッドを使用する必要があります(UIImageバックグラウンド スレッドで を構築する場合など、特に明記されていない限り)。

weakSelf現在のコードに関する 1 つのコメント:使用する前に、強力なローカル変数に割り当てる必要があります。そうしないと、条件が通過する可能性がありますが、weakSelf実際に使用する前に無効になる可能性があります。それは次のようになります

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    UIImage *tmpImage = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];

    __strong __typeof__(weakSelf) strongSelf = weakSelf;
    if ([strongSelf.scrollView viewWithTag:tagNumber] != nil){

        dispatch_async(dispatch_get_main_queue(), ^{
            __strong __typeof__(weakSelf) strongSelf = weakSelf;
            if ([strongSelf.scrollView viewWithTag:tagNumber]!= nil){
                UIImageView * tmpImageView = (UIImageView*)[strongSelf.scrollView viewWithTag:tagNumber];
                tmpImageView.image = tmpImage;
            }
        });
    }
});

技術的には、バックグラウンド キューの最初の条件でこれを行う必要はありません。一度しか逆参照していないためです。コース。

于 2013-01-17T00:37:29.967 に答える
1

はい、メイン スレッドで UI の変更を行う必要があるため、メイン スレッドを使用する必要があります。

GCD の使用に関しては、デバイスのマルチコアを利用するために使用されます。強い自分と弱い自分について

強力な自己: 強力な自己が必要になる場合があります。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
(<your class> *) *strongSelf = weakSelf;
    UIImage *tmpImage = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];

    if ([strongSelf.scrollView viewWithTag:tagNumber] != nil){

        dispatch_async(dispatch_get_main_queue(), ^{

            if ([strongSelf.scrollView viewWithTag:tagNumber]!= nil){
                UIImageView * tmpImageView = (UIImageView*)[strongSelf.scrollView viewWithTag:tagNumber];
                tmpImageView.image = tmpImage;
            }
        });
    }
});

API呼び出しを行うビューがあり、時間がかかるため、別のビューに切り替えても、画像をダウンロードしたい場合は、ブロックが自己を所有しているため画像がダウンロードされるため、ストロングを使用するとします。

弱い自己: 上記の状況で、別のビューに移動したときに画像をダウンロードしたくない場合は、ブロックが自己を所有していないため、弱い自己を使用します。

于 2013-01-17T10:01:20.560 に答える
1

で画像をレンダリングする必要がある場合はUIImageView、メイン スレッドでこれを行う必要があります。コードに示されているように、メイン キューで実行しないと機能しません。UI レンダリングの場合も同様です。

if ([weakSelf.scrollView viewWithTag:tagNumber]!= nil){
    UIImageView * tmpImageView = (UIImageView*)[weakSelf.scrollView viewWithTag:tagNumber];
    tmpImageView.image = tmpImage;
}

Apple のドキュメントに従って、

スレッドに関する考慮事項:アプリケーションのユーザー インターフェイスに対する操作は、メイン スレッドで行う必要があります。したがって、常にアプリケーションのメイン スレッドで実行されているコードから UIView クラスのメソッドを呼び出す必要があります。これが厳密に必要でない唯一の場合は、ビュー オブジェクト自体を作成するときですが、他のすべての操作はメイン スレッドで実行する必要があります。

于 2013-01-17T00:39:05.133 に答える
0

Kevin Ballard によって提案されたコードで strongSelf を使用しない場合、weak が nil アウトされるためにクラッシュする可能性があります。

また、作成時に strong が非 nil であることを確認することもお勧めします。

strongSelf = weakSelf

   if(strongSelf)
   {
       // do your stuff here 
   }
于 2014-01-10T15:53:33.090 に答える