在Swift(iOS)中逐个调用异步任务

在Swift(iOS)中逐个调用异步任务,ios,swift,asynchronous,Ios,Swift,Asynchronous,对于iOS天气应用程序,我在尝试使用swift中的dispatch async逐个运行多个异步任务时遇到问题。我希望我的“update()”函数: 获取用户的位置(并将纬度和经度存储在类变量中) 位置服务完成后,根据新填充的lat和long变量调用天气API API调用(以及后续的XML解析)完成后,更新UI(iOS表视图) (对我放松点,我是一名自学成才的程序员,所以我假设你们当中经验更丰富的人能够指出各种错误!任何帮助都将不胜感激。) var纬度:String=“” 变量经度:Strin

对于iOS天气应用程序,我在尝试使用swift中的dispatch async逐个运行多个异步任务时遇到问题。我希望我的“update()”函数:

  • 获取用户的位置(并将纬度和经度存储在类变量中)
  • 位置服务完成后,根据新填充的lat和long变量调用天气API
  • API调用(以及后续的XML解析)完成后,更新UI(iOS表视图)
(对我放松点,我是一名自学成才的程序员,所以我假设你们当中经验更丰富的人能够指出各种错误!任何帮助都将不胜感激。)

var纬度:String=“”
变量经度:String=“”
var locationManager:CLLocationManager!
var forecastData:Weather=Weather()//Weather类有自己的异步NSURLSession,名为retrieveForecast()
//它调用开放天气图API并解析XML
func刷新(){
//这是我不知道自己在做什么的地方:
let group=dispatch\u group\u create()
调度组输入(组)
调度异步(调度获取全局队列(调度队列优先级高,0)){
self.getLocation()
派遣组休假(组)
}
调度\组\通知(组、调度\获取\全局\队列(调度\队列\优先级\高,0)){
self.getWeather()
}
self.updateUI()/…我知道这是在完全错误的地方!
}
//获取手机位置的功能:
func getLocation(){
locationManager=CLLocationManager()
locationManager.delegate=self
locationManager.desiredAccuracy=KCallocationAccuracyHundredMeters
locationManager.RequestWhenUseAuthorization()
locationManager.distanceFilter=100.0
locationManager.startUpdatingLocation()
}
func locationManager(管理器:CLLocationManager,didUpdateLocations位置:[CLLocation]){
self.locationManager.stopUpdatengLocation()
manager.stopUpdateLocation()
对于项目:位置中的任何对象{
如果let location=项目as?CLLocation{
如果位置水平精度<1000{
manager.stopUpdateLocation()
self.latitude=字符串(location.coordinate.latitude)
self.longitude=String(location.coordinate.longitude)
}
}
}
}
//用于下载和解析forecastData对象中的天气数据的函数
func getWeather(){
让我们来看看。”http://api.openweathermap.org/data/2.5/forecast?lat=“+自我纬度
+“&lon=“+self.longide+”&mode=xml&appid=“+self.openweathermappikey”
NSLog(“使用api请求调用的getWeather:\(apiCall)”)
self.forecastData.retrieveForecast(apiCall)
}

对于任何异步操作,使用finish回调是一种很好的方式。 在您的情况下,如果您已经实现了对
getLocation
getWeather
的回调,您将永远不需要
dispatch\u group
,您只需从
getLocation
的回调调用
getWeather
的回调调用
refreshUI

    var latitude: String = ""
    var longitude: String = ""
    var locationManager: CLLocationManager!
    var forecastData: Weather = Weather() // the weather class has it's own asynchronous NSURLSession called retrieveForecast() 
                                          // which calls the Open Weather Map API and parses the XML

    func refresh() {
        self.getLocation()
    }


    // function(s) to get phone's location:
    func getLocation() {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.requestWhenInUseAuthorization()
        locationManager.distanceFilter = 100.0
        locationManager.startUpdatingLocation()
    }
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        self.locationManager.stopUpdatingLocation()
        manager.stopUpdatingLocation()
        for item: AnyObject in locations {
            if let location = item as? CLLocation {
                if location.horizontalAccuracy < 1000 {
                    manager.stopUpdatingLocation()
                    self.latitude = String(location.coordinate.latitude)
                    self.longitude = String(location.coordinate.longitude)
                    self.getWeather()
                }
            }
        }
    }

    // function to download and parse the weather data within forecastData object
    func getWeather() {
            let apiCall = "http://api.openweathermap.org/data/2.5/forecast?lat=" + self.latitude
            + "&lon=" + self.longitude + "&mode=xml&appid=" + self.openWeatherMapAPIKey
        NSLog("getWeather called with api request: \(apiCall)")
        self.forecastData.retrieveForecast(apiCall)
        // assuming that self.forecastData.retrieveForecast(apiCall) is completely synchronous, we can call updateUI below
        self.updateUI()
    }

在开始学习闭包/块之后,我终于找到了我的答案,我想与大家分享一下。我需要做的是在Weather类中的参数中添加一个闭包,当XML解析完成时,该闭包返回一个布尔值,并允许我在更新UI之前在视图控制器中等待该情况发生。我希望这能帮助其他寻找类似答案的人,如果任何专业人士能够让这段代码变得更好,请添加评论

...

// getWeather function in my View Controller (called from location manager)
  func getWeather() {
            let apiCall = "http://api.openweathermap.org/data/2.5/forecast?lat=" + self.latitude
            + "&lon=" + self.longitude + "&mode=xml&appid=" + self.openWeatherMapAPIKey
        NSLog("getWeather called with api request: \(apiCall)")
        self.forecastData.retrieveForecast(apiCall, completion: { success in
            if success {
                self.updateUI()
            } else {
                NSLog("Parse unsuccessful")
                // I'll handle the issue here
            }
        });
  }
…在Weather类函数中:

func retrieveForecast(url: String, completion: ((Bool)->())?) {
    self.reset()
    let apiCall = NSURL(string: url)
    let urlRequest: NSURLRequest = NSURLRequest(URL: apiCall!)
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithRequest(urlRequest) {
        (data, response, error) -> Void in
        self.xmlParser = NSXMLParser(data: data!)
        self.xmlParser.delegate = self
        let success: Bool = self.xmlParser.parse()
        if !success {
            NSLog("Did not parse. \(error?.localizedDescription)")
            completion?(false)
        } else {
            self.currentParsedElement = ""
            self.retrievingForecast = false
            completion?(true)
        }
    }
    task.resume()
}

您正在寻找如何同步运行代码。只要这样做,不要尝试一些高级技术如何同步异步代码,如果你真的需要同步运行它谢谢你的建议@user3441734,虽然我不能把它全部放到主线程中,因为它不允许
getLocation
获得
getWeather
需要的坐标,但同步代码可以在自己的单独队列中运行。它与主队列无关。同步意味着函数在结果可用之前不会返回。因为您还需要一个接一个地连续运行代码,所以只需在自己的串行队列中运行所有代码。整个代码块可以同步运行,也可以与主队列并行运行感谢@purrminator,这看起来比使用
dispatch\u groups
更好地解决我的问题-我将研究如何立即创建回调!我可以看到代码运行得更好,但是
self.forecastData.retireveForecast(apiCall)
正在启动一个
NSURLSession
,即从internet下载一个XML,然后对其进行解析,所以一旦XML解析完成,可能需要运行
self.updateUI()
。。。虽然我不知道该怎么办that@AlexSmith您必须了解更多关于委派模式以及如何使用区块的信息,这听起来像是一些有用的后续步骤。感谢您对我有耐心,并抽出时间与我分享一些代码!我试着同时阅读HealthKit上的台阶、距离和爬的楼层,而派遣团队在这方面做得很好。有没有办法加快速度?我可以请求它在更高优先级的队列上运行吗?再次感谢@purrminator!
...

// getWeather function in my View Controller (called from location manager)
  func getWeather() {
            let apiCall = "http://api.openweathermap.org/data/2.5/forecast?lat=" + self.latitude
            + "&lon=" + self.longitude + "&mode=xml&appid=" + self.openWeatherMapAPIKey
        NSLog("getWeather called with api request: \(apiCall)")
        self.forecastData.retrieveForecast(apiCall, completion: { success in
            if success {
                self.updateUI()
            } else {
                NSLog("Parse unsuccessful")
                // I'll handle the issue here
            }
        });
  }
func retrieveForecast(url: String, completion: ((Bool)->())?) {
    self.reset()
    let apiCall = NSURL(string: url)
    let urlRequest: NSURLRequest = NSURLRequest(URL: apiCall!)
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithRequest(urlRequest) {
        (data, response, error) -> Void in
        self.xmlParser = NSXMLParser(data: data!)
        self.xmlParser.delegate = self
        let success: Bool = self.xmlParser.parse()
        if !success {
            NSLog("Did not parse. \(error?.localizedDescription)")
            completion?(false)
        } else {
            self.currentParsedElement = ""
            self.retrievingForecast = false
            completion?(true)
        }
    }
    task.resume()
}