Swift从api可能的线程问题获得价值
问题描述:
我有一个函数,使用谷歌的地方api做api请求。从API响应数据中,我捕获一个值并尝试将其设置为一个变量。该功能在另一个功能中调用。然后我尝试访问该变量,但不幸的是该变量尚未包含该值。这似乎是一个线程问题,但我不知道如何解决它。Swift从api可能的线程问题获得价值
更新: 我已根据回复更新了代码。不幸的是,我仍然无法使用api请求中的值访问变量。我已经重写了执行api请求使用完成处理程序的函数。 mapView(mapView:GMSMapView !, didTapInfoWindowOfMarker标记:GMSMarker!)是google maps框架中的一个函数。我是否需要重写这个以及使用完成处理程序?
//可变
var website = ""
//代码与API请求
func getWebsite2(id: String, completion: (result: String) -> Void) {
var url = NSURL(string: "https://maps.googleapis.com/maps/api/place/details/json?placeid=\(id)&key=AIzaSyAWV1BUFv_vcedYroVrY7DWYuIxcHaqrv0")
self.dataTask = defaultSession.dataTaskWithURL(url!) {
data, respnse, error in
let json : AnyObject
do {
json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
var dictionArr = json["result"]
self.website = dictionArr!!["website"] as! String
print(self.website)
}
catch {
print(error)
}
}
self.dataTask?.resume()
}
//第二功能
func mapView(mapView: GMSMapView!, didTapInfoWindowOfMarker marker: GMSMarker!) {
let storeMarker = marker as! PlaceMarker
self.getWebsite2(storeMarker.id!) {
(result: String) in
print("inside did tap")
print(self.website)
// problem still here
// above two lines of code never run
}
self.performSegueWithIdentifier("toWebView", sender: nil)
}
//我初始化defaultSession和dataTask这样。
let defaultSession = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
var dataTask: NSURLSessionDataTask?
答
您没有调用传入getWebsite2
函数的完成处理函数。这个(伪)代码显示了如何从服务器获取字符串并将其传递给在didTapInfoWindowOfMarker
中调用的闭包。
func getWebsite2(id: String, completion: (result: String) -> Void) {
self.dataTask = defaultSession.dataTaskWithURL(url!) {
data, response, error in
// now on background thread
let someStringFromNetwork = data[0]
dispatch_async(dispatch_get_main_queue(),{
completion(someStringFromNetwork)
})
}
}
答
首先不要强制展开变量,并且在需要的地方总是使用do{} catch{}
。
这个小代码块,告诉你应该如何处理try
和if let
条件:
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! [String:AnyObject]
if let dictionary = jsonObject["result"] as? [String: String] {
self.website = dictionary["website"]
} else {
print("Parse error")
}
} catch {
print("JSON error: \(error)")
}
其次defaultSession.dataTaskWithURL
是将只设置数据时,他将完成异步请求。
在另一个世界中,您尝试在请求未完成时打印值。 为了解决你的问题,你应该使用Completion Handlers。
网络请求是异步的,所以其余的代码在网络请求完成之前运行。您需要编写函数'getWebsite2'来获取完成块,与'defaultSession.dataTaskWithURL'允许您传入完成块的方式相同 –
感谢您和Oleg的回复。我目前正在跟踪你和Oleg的建议并尝试使用完成处理程序。我会在发现更新时发布更新 – ray
不清楚如何从您的snipplet中初始化defaultSession。假设它是对'NSURLSession.shared()'的本地引用,代码将在不同的线程上运行并导致数据竞争。你需要在'dispatch_async(dispatch_get_main_queue()){...}'封闭中包装'self.website = ...'。 – user2378197