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