SVProgressHUD代码无序执行

时间:2018-08-01 19:59:18

标签: ios swift svprogresshud

我正在使用NextBus API构建公交车预测应用程序,该应用程序将帮助用户获取预测时间和公交车信息。我实现了一个功能,该功能可以获取用户的当前位置和选定的地址,并返回10条公交路线的列表,以最大程度地减少行驶距离和时间。

以下是触发上述功能的@IBAction

@IBAction func findAWayPressed(_ sender: UIButton) {
    // Hide confirm button.
    confirmButton.isHidden = true

    // Setup loading HUD.
    let blue = UIColor(red: 153/255, green: 186/255, blue: 221/255, alpha: 1.0)
    SVProgressHUD.setBackgroundColor(blue)
    SVProgressHUD.setStatus("Finding a way for you...")
    SVProgressHUD.setBorderColor(UIColor.black)
    SVProgressHUD.show()

    // Finds a list of ten bus routes that minimizes the distance from the user and their destination.
    WayFinder.shared.findAWay(startCoordinate: origin!, endCoordinate: destination!)

    SVProgressHUD.dismiss()
}

问题是confirmButton.isHidden = true和SVProgressHUD行似乎仅在执行WayFinder.shared.findAWay()之后才执行任何操作。 HUD会显示一会儿,然后SVProgressHUD.dismiss()立即将其关闭。

这是findAWay函数:

func findAWay(startCoordinate: CLLocationCoordinate2D, endCoordinate: CLLocationCoordinate2D) {
    // Get list of bus routes from NextBus API.
    getRoutes()

    guard !self.routes.isEmpty else {return}

    // Initialize the the lists of destination and origin stops.
    closestDestinations = DistanceData(shortestDistance: 1000000, stops: [])
    closestOrigins = DistanceData(shortestDistance: 1000000, stops: [])

    // Fetch route info for every route in NextBus API.
    var routeConfigsDownloaded: Int = 0
    for route in routes {
        // Counter is always one whether the request fails
        // or succeeds to prevent app crash.
        getRouteInfo(route: route) { (counter) in
            routeConfigsDownloaded += counter
        }
    }

    while routeConfigsDownloaded != routes.count {}

    // Iterate through every stop and retrieve a list
    // of 10 possible destination stops sorted by distance.
    getClosestDestinations(endCoordinate: endCoordinate)
    // Use destination stop routes to find stops near
    // user's current location that end at destination stops.
    getOriginStops(startCoordinate: startCoordinate)

    // Sort routes by adding their orign distance and destination
    // distance and sorting by total distance.
    getFoundWays()
}

private func getRouteInfo(route: Route, completion: @escaping (Int) -> Void) {
    APIWrapper.routeFetcher.fetchRouteInfo(routeTag: route.tag) { (config) in
        if let config = config {
            self.routeConfigs[route.tag] = config
        } else {
            print("Error retrieving route config for Route \(route.tag).")
        }
        completion(1)
    }
}

为什么@IBAction中的代码不能按顺序执行?在调用findAWay之前,hud怎么不显示在屏幕上?有什么想法吗?

1 个答案:

答案 0 :(得分:1)

因此,您将需要对“主线程”及其工作方式进行一些阅读。也许UNDERSTANDING THE IOS MAIN THREAD

基本上,您是在要求系统显示HUD,然后执行我认为是长时间运行并阻塞的操作,然后关闭主线程中的HUD。

在该方法存在之前,系统不可能显示HUD,因为它将作为下一个循环的一部分(绘画/布局/其他重要内容)。在这种情况下,我倾向于使用某种“承诺” API,例如PromiseKitHydra,因为它会极大地简化线程希望。

基本意图是-在主线程上,使用后台线程显示HUD,执行查询,完成后关闭HUD,但在主线程上执行。

可能看起来像这样。

SVProgressHUD.show()
DispatchQueue.global(qos: .userInitiated).async {
    WayFinder.shared.findAWay(startCoordinate: origin!, endCoordinate: destination!)
    DispatchQueue.main.async {
        SVProgressHUD.dismiss()
    }
}

现在请记住,永远不要从主线程上下文之外修改UI,如果OS检测到它,将会使您的应用程序崩溃!

我也可以考虑使用DispatchSemaphore代替“狂奔” while-loop,所以代替。.

// Fetch route info for every route in NextBus API.
var routeConfigsDownloaded: Int = 0
for route in routes {
    // Counter is always one whether the request fails
    // or succeeds to prevent app crash.
    getRouteInfo(route: route) { (counter) in
        routeConfigsDownloaded += counter
    }
}

while routeConfigsDownloaded != routes.count {}

您可能会使用类似...

let semaphore = DispatchSemaphore(value: routes.count)
// Fetch route info for every route in NextBus API.
var routeConfigsDownloaded: Int = 0
for route in routes {
    // Counter is always one whether the request fails
    // or succeeds to prevent app crash.
    getRouteInfo(route: route) { (counter) in
        semaphore.signal()
    }
}

semaphore.wait()

这将执行相同的操作,但效率更高