GCD – 用于更新UIImageView的主要vs后台线程

我是GCD的新手,并且正在放松自己。

背景:我正在使用ALAssetsLibrary为UIScrollView执行延迟加载例程。 当我的UIScrollView加载时,我使用aspectRatioThumbnails的aspectRatioThumbnails填充它,然后当用户滚动时,我调用下面的例程来加载当前正在显示的ALAsset的fullScreenImage 。 这似乎工作。

(如果有人有一个更好的延迟加载例程,请发表评论,我已经看了所有我能find的,加上WWDCvideo,但他们似乎处理更多的瓷砖或比我需要更复杂)

我的问题:我使用后台线程来处理加载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; } }); } }); } 

是的,无论何时触摸UIImageView或任何其他UIKit类(除非另有说明,例如在后台线程上构buildUIImage时),都需要使用主线程。

一个关于你当前的代码的评论:你需要在使用它之前将weakSelf分配到一个强大的局部variables中。 否则,你的条件可能会通过,但是然后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; } }); } }); 

从技术上讲,您不需要在后台队列中的第一个条件中执行此操作,因为您只需在此处解除引用,但在触摸之前,将弱variables存储为强variables总是个好主意课程。

如果您需要在UIImageView渲染图像,则需要在主线程中执行此操作。 它不会工作,除非您在主队列中执行,如代码中所示。 任何UI渲染都是如此。

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

按照苹果文档 ,

线程考虑事项:对应用程序用户界面的操作必须在主线程上进行。 因此,你应该总是从应用程序主线程中运行的代码调用UIView类的方法。 唯一可能不是严格需要的是创build视图对象本身,但所有其他操作应该在主线程上进行。

是的,您需要使用主线程,因为任何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调用的视图,这需要时间,所以你切换回另一个视图,但你仍然希望图像被下载,然后使用强,因为块拥有自我,所以图像下载。

虚弱的自我 :如果在上述情况下,一旦你移动到不同的视图,你不希望图像下载,然后使用弱自我,因为块没有任何自我。

如果你不会在Kevin Ballard所build议的代码中使用strongSelf,那么可能会导致崩溃,

也是一个很好的做法,甚至可以在创build时检查强大的非零

 strongSelf = weakSelf if(strongSelf) { // do your stuff here }