如何使此代码在Swift上异步

问题描述 投票:1回答:1

我有一个包含照片图像URL的字符串数组。我有一个自定义布局,我需要将字符串数组转换为UIImage,然后获取它们的大小。这是我的代码:

extension PhotoFeedViewController: CustomLayoutDelegate {

func collectionView(_ collectionView: UICollectionView, sizeOfPhotoAtIndexPath indexPath: IndexPath) -> CGSize {

    let bodyImage = UIImageView()
    let url = URL(string: collectionPhotos[indexPath.row])

    let data = try? Data(contentsOf: url!)
//        DispatchQueue.main.async {
        if let imageData = data {
            bodyImage.image = UIImage(data: imageData)
        }
//        }

    return bodyImage.image?.size ?? CGSize(width: 100, height: 100)
   }
}

此代码有效,但是有问题。当我启动该应用程序时,由于所有图像都是同步的,因此图像会在所有图像加载后显示。

如果您取消注释:

DispatchQueue.main.async {

返回的属性为空,并且看不到Dispatch块中的代码

我如何使此代码异步,以使图像的大小异步传递,并且用户不等待图像的全部负载显示在屏幕上?不使用库。

对不起,我的英语。

ios arrays swift uiimage dispatch-async
1个回答
1
投票

您完全正确,同步请求是一个问题。 (而且我们经常使用URLSession,而不仅仅是将其包装在async调用中。)

但是您可能必须从根本上重新考虑此过程。您确实不想下载图像,而是可以确定图像的大小,只是可以在cellForItemAt中重新下载图像。 (而且我不建议您依靠URLCache来拯救您。)理想情况下,如果此URL数组的源可以同时返回图像的大小,并会切掉Gordian结。如果您具有URL列表和相应的图像大小,则可以消除下面讨论的所有问题。

失败,您有两种基本选择:

  1. 您是否要在UI中强制所有图像具有相同的大小,而不管实际图像的大小如何(例如,并使用“纵横比填充”内容模式)?那将是最简单的。

  2. 您是否要假设某个标准大小,直到下载图像,然后在完成相应的图像下载后重新加载该特定单元格(可能导致重新布局所有内容)?由于您无法始终控制异步图像的返回顺序,因此有时会导致运入集合视图中的更改受到破坏。
  3. 后一种方法有很多小的并发症:

  • 编写一个下载管理器,跟踪下载的图像以缓存先前的下载(理想情况下,既在内存中,又在持久性存储中)。通过使用缓存,如果将单元格滚动到视图中,它将检查是否已经下载了图像,如果已下载,则使用它。例如。当您在收藏夹视图中向后滚动时,您不想对先前下载的图像发起网络请求。

  • 在异步图像检索过程中,您不仅会更新图像视图,而且会完全重新加载与该单元格的IndexPath关联的单元格。这将触发它再次查询图像的大小。
  • 因此,“此单元格的大小”例程将有效地表示“我是否下载了图像?如果是,则返回其大小;如果没有初始化异步下载(完成后将重新加载单元格)并返回一些占位符大小。” cellForItemAt中会有类似的逻辑。
  • 其他一些注意事项:

  • 您正在返回图像的尺寸。我不知道您如何使用此方法,但是在基于图像的大小(通常以像素为单位)确定图像视图的大小(以磅为单位)之前,通常我们会考虑设备的尺寸。] >

  • 如果您还没有这样做,那么在解决上述问题时,您可能希望实施预取。如果您在滚动到集合视图中的特定内容偏移量时已经下载了图像,则这将减少任何令人讨厌的单元格调整大小。
© www.soinside.com 2019 - 2024. All rights reserved.