首页 > 解决方案 > 如何等待函数快速完成

问题描述

我有这个功能,我将用户的取货和送货地址转换为坐标。将地址转换为坐标后,我想计算它们的距离。我使用 REST api 转换和计算这些。

这些是我获得坐标的功能

        if let url = URL(string: "APIURL"){
        

        let session = URLSession(configuration: .default)
        
        let task  = session.dataTask(with: url) { (data, resp, err) in
            if err != nil{
                print("Error converting adress to coordinates: \(err)")
            }
            
            if let safeData = data{
                
                self.parseJSON(with: safeData, adressType: "From")
            }
        }
        
        task.resume()
    }
    
    if let url = URL(string: "APIURL"){
        
        let session = URLSession(configuration: .default)
        
        let task  = session.dataTask(with: url) { (data, resp, err) in
            if err != nil{
                print("Error converting adress to coordinates: \(err)")
            }
            
            if let safeData = data{
                
                self.parseJSON(with: safeData, adressType: "To")
            }
        }
        
        task.resume()
    }

所以我想要的是让这两个完成。在我得到这些值之后,我想计算距离。

这是距离请求

        if let url = URL(string:"APIURL"){
        

        let session = URLSession(configuration: .default)
        
        let task = session.dataTask(with: url) { (data, res, err) in

            if err != nil{
                print("Could not start task to fetch distance")
            }
            
            if let safeData = data{
                
                self.parseDistanceJSON(with: safeData)
            }
        }
        
        task.resume()
    }

目前,它们都驻留在这一功能中

 func fetchDistance(fromAdress: String, toAdress: String){
          
         if let url = URL(string: "APIURL"){
                 // Fetch for fromAdress...
             }
           if let url = URL(string: "APIURL"){
                 // Fetch for toAdress...
             }

           if let url = URL(string: "APIURL"){
                 // Fetch for distance between fromAdress and toAdress...
             }
    }

唯一的问题是我希望它们按照您在代码中看到的确切顺序执行。但现在,这不是我能控制的。有时最后一次提取会先执行,有时它们会同时执行。

标签: iosswiftswiftui

解决方案


您的第三个功能取决于前两个的数据,但前两个是独立的。

DispatchGroup前两个完成后,您可以使用 a来执行第三个函数。前两个函数按什么顺序完成并不重要。

您确实需要考虑一个或多个网络操作可能会失败。

由于这些网络操作是异步的,因此您需要将完成处理程序传递给fetchDistance并在工作完成时调用它。

就像是


enum MyError: Error {
    case locationNotFound
}

func fetchDistance(fromAdress: String, toAdress: String, completion: @escaping (Result<Double, Error>) -> Void) {

    var firstLocation: CLCoordinate2D?
    var secondLocation: CLLocationCoordinate2D?
    var error: Error?

    let dispatchGroup = DispatchGroup()

    dispatchGroup.enter();

    self.fetchLocation(for: fromAddress) { result in
        switch result {
            case .failure(let operationError):
                operationError = operationError;
            case .success(let location):
                firstLocation = location
        }

        dispatchGroup.leave()

    }

    dispatchGroup.enter();

    self.fetchLocation(for: toAddress) { result in
        switch result {
            case .failure(let operationError):
                operationError = operationError;
            case .success(let location):
                secondLocation = location
        }

        dispatchGroup.leave()

    }

    dispatchGroup.notify() {
        guard error != nil else {
            completion(.failure(error))
            return
        }

        guard let first = firstLocation, let second = secondLocation else {
            completion(.failure(MyError.locationNotFound)
            return
        }

        self.findDistance(from: first, to: second) { result in
            completion(result)
        }
    }
}

func fetchLocation(for address: string, completion: completion: @escaping (Result<CLLocationCoordinate2D, Error>) -> Void) {

    // Perform API call to get lat & Lon for address.
    // Convert lat & lon to CLLocationCoordinate2D
    // Invoke completion
    /// completion(.success(location))
}

func findDistance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D ,completion: completion: @escaping (Result<CLLocationCoordinate2D, Error>) -> Void) {

    // Perform API call to get distance as double
    // Invoke completion
    /// completion(.success(distance))
}

推荐阅读