如何等待下载完成后再继续?

时间:2021-04-01 17:33:03

标签: swift asynchronous grand-central-dispatch

我有这个代码块。它从 API 获取数据并将其添加到 locationDetails 数组中,该数组是单例的一部分。

private func DownloadLocationDetails(placeID: String) {
        let request = AF.request(GoogleAPI.shared.getLocationDetailsLink(placeID: placeID))
        request.responseJSON { (data) in
            
            guard let detail = try? JSONDecoder().decode(LocationDetailsBase.self, from: data.data!),
                  let result = detail.result else {
                print("Something went wrong fetching nearby locations.")
                return
            }
            DownloadManager.shared.locationDetails.append(result)
        }
    }

这个代码块就是有问题的块。我正在创建一个只下载新信息并保留任何旧信息的缓存系统。这样做是为了节省对 API 的调用并提高性能。行 DownloadLocationDetails(placeID: placeID) 对我来说是一个问题,因为如果我执行这行代码,它会在等待下载完成时使用不必要的 API 调用一遍又一遍地继续循环。我如何有效地管理这种情况?

func GetLocationDetail(placeID: String) -> LocationDetail {
        for location in locationDetails {
            if location.place_id == placeID { return location }
        }
        DownloadLocationDetails(placeID: placeID)
        return GetLocationDetail(placeID: placeID)
    }

我希望这个 GetLocationDetail(....) 在用户与界面对象交互时被调用,那么我如何确保调用它的视图能够正确通知下载已完成?

我尝试使用闭包,但我无法让它以我想要的方式返回。我在单例上有一个属性,我想设置这个值,以便可以全局调用它。我也在考虑使用 GCD,但我不确定它的结构。

1 个答案:

答案 0 :(得分:0)

通常,这种模式的模式是将您创建的请求对象存储在 DownloadLocationDetails 中,以便您可以在进行另一次调用之前检查它是否处于活动状态。如果您只想一次支持一个,那么它就像保留对请求对象的裸引用一样简单,但是您可以制作一个以 placeID 为键的请求对象字典(并且您可能想要考虑最大请求数,并排队额外的请求)。

然后诀窍是在给定的请求对象完成时得到通知。有几种方法可以做到这一点,例如保留一个回调列表以在完成时调用,但最简单的方法可能只是稍微重构一下代码,以便在请求完成时始终更新您的 UI,所以有些事情喜欢:

private func DownloadLocationDetails(placeID: String) {
        let request = AF.request(GoogleAPI.shared.getLocationDetailsLink(placeID: placeID))
        request.responseJSON { (data) in
            
            guard let detail = try? JSONDecoder().decode(LocationDetailsBase.self, from: data.data!),
                  let result = detail.result else {
                print("Something went wrong fetching nearby locations.")
                return
            }
            DownloadManager.shared.locationDetails.append(result)
            // Notify the UI to refresh for placeID
        }
    }