UIImage initWithData:阻止 UI 异步调度线程?

UIImage initWithData: blocking UI thread from async dispatch?

以下代码正在阻止 UI(在图像加载完成之前无法点击另一个选项卡)。

我已经通过注释该行并保持下载(我知道这是异步发生的并在主线程上调用完成处理程序)来验证 UIImage *imageToShow = [[UIImage alloc] initWithData:data]; 调用是罪魁祸首。

在只有initWithData:行被注释的情况下,UI响应是可以的。但是,如果在后台清楚地调度,那条线怎么会是支撑 UI 的线呢?

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    ...

    [objectStore getFileInContainer:@"public_images" filename:filename completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            UIImage *imageToShow = [[UIImage alloc] initWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                collectionImageView.image = imageToShow;
            });
        });
    }];

    ...
}

最有可能导致 UI 挂起的部分是图像对图像视图的实际设置,特别是如果图像很大,因为这确实(而且必须)发生在主线程上.

我建议您先在后台线程中操作时调整或缩小图像。然后一旦你调整了图像的大小,跳回到主线程并将它分配给``imageView.image```。

这是调整 UI图像大小的一种方法的简单示例:Resize UIImage by keeping Aspect ratio and width

UIImage 直到第一次实际 used/drawn 才读取和解码图像。要强制此工作在后台线程上进行,您必须在执行主线程 -setImage: 调用之前 use/draw 后台线程上的图像。许多人发现这违反直觉。我在 another answer.

中对此进行了相当详细的解释