iOS - 在转到下一个视图控制器之前如何等待代码完成?

iOS - How do I wait for the code to finish before going to the next view controller?

我对编码还很陌生,不知道该怎么做。我试图从一个地址获取用户的地理坐标,使用坐标计算出一些值,然后转到另一个视图控制器,其中一些代码将 运行 显示我计算出的值。问题是它找到用户坐标,然后转到下一个视图控制器,它没有显示它所需的计算数据,然后尝试计算第一个控制器所需的值。如何按顺序将此代码获取到 运行?

我的代码

@IBAction func BSearch(_ sender: UIButton) {
    getCoordinate(addressString: AdressInput) { coordinate, error in
        if error != nil {
            // Error
            return
        } else {
            user_lat = String(format: "%f", coordinate.latitude)
            user_long = String(format: "%f", coordinate.longitude) // Program gets this first
            self.getData(savedLat: user_lat, savedLong: user_long) // Lastly goes here
        }
    }
    performSegue(withIdentifier: "TimeNavigation", sender: self) // Goes here second
}

函数

func getCoordinate(addressString: String, completionHandler: @escaping (CLLocationCoordinate2D, NSError?) -> Void ) {
    let geocoder = CLGeocoder()
    geocoder.geocodeAddressString(addressString) { (placemarks, error) in
        if error == nil {
            if let placemark = placemarks?[0] {
               let location = placemark.location!
               completionHandler(location.coordinate, nil)
               return
            }
        }
        completionHandler(kCLLocationCoordinate2DInvalid, error as NSError?)
    }
}

获取数据函数

func getData(savedLat: String, savedLong: String) {
    guard let url = URL(string: "http://127.0.0.1:5000/api/lat/\(savedLat)/long/\(savedLong)") else{return}

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let data = data else { return }

        var dataAsString = String(data: data, encoding: .utf8)

        let splits = dataAsString?.components(separatedBy: "|")

        let Counter:Int = splits?.count ?? 0

        for n in 0...(Counter-1){
            let splits2 = splits?[n].components(separatedBy: ",")
            for x in 0...9 {
                dataArray[n][x] = String(splits2?[x] ?? "nil")
            }
        }
    }.resume()
}

将它写在闭包内,因为你的 performSegue 在闭包结果之前执行......所以将它写在闭包内但在主线程上

更新您的 getData 函数

typealias CompletionHandler = (_ success:Bool) -> Void
    func getData(savedLat:String,savedLong:String, completionBlock:@escaping CompletionHandler){

    guard let url = URL(string: "http://127.0.0.1:5000/api/lat/\(savedLat)/long/\(savedLong)") else{return}

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let data = data else {
            completionBlock(false)
            return
        }

        var dataAsString = String(data: data, encoding: .utf8)

       let splits = dataAsString?.components(separatedBy: "|")
       let Counter:Int = splits?.count ?? 0

            for n in 0...(Counter-1){
               let splits2 = splits?[n].components(separatedBy: ",")
                    for x in 0...9 {
                       dataArray[n][x] = String(splits2?[x] ?? "nil")

                               }
                            completionBlock(true)
                         }

                  }.resume()
       }

然后是你的 BSearch 方法

@IBAction func BSearch(_ sender: UIButton) {
   getCoordinate(addressString: "AdressInput") { coordinate, error in
      if error != nil {
         // Error
         return
      }
      else {

        user_lat = String(format: "%f", coordinate.latitude)
        user_long = String(format: "%f", coordinate.longitude) // Program gets this first
        self.getData(savedLat: "user_lat", savedLong: "user_long", completionBlock: {[weak self] success in

        DispatchQueue.main.async {
          self?.performSegue(withIdentifier: "TimeNavigation", sender: self)
          }
                }) // Lastly goes here
              }
          }
}

您在 getCordinate 函数的范围之外调用 performSegue,这就是为什么它在单击按钮时被调用而不是等待完成处理程序完成。

只要把它移到里面就可以了。

@IBAction func BSearch(_ sender: UIButton) {
   getCoordinate(addressString: AdressInput) { coordinate, error in
            if error != nil {
              // Error
              return
            }
            else {

               user_lat = String(format: "%f", coordinate.latitude)
               user_long = String(format: "%f", coordinate.longitude) // Program gets this first
               self.getData(savedLat: user_lat, savedLong: user_long) // Lastly goes here
               DispatchQueue.main.async { //when performing UI related task, it should be on main thread
                 self.performSegue(withIdentifier: "TimeNavigation", sender: self) 
               }

              }
    }
}