问题
I am new to swift language and I have problem that I can't solve.
After running my app i get output of empty String: nil
So, my question is how to add value to variable inside closure?
Because when I add line inside closure print(self.latLong) I get output of coordinates, but I need that value inside of variable because I need to manipulate with that variable later in my code and I don't want to write all functionality inside that closure
This is my code:
import UIKit
import CoreLocation
import Firebase
var latLong: String!
override func viewDidLoad() {
super.viewDidLoad()
findCordiante(adress: "Cupertino, California, U.S.")
print(latLong)
}
func findCordiante(adress:String){
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(adress) {
placemarks, error in
if (placemarks != nil){
let placemark = placemarks?.first
let lat = placemark?.location?.coordinate.latitude
let lon = placemark?.location?.coordinate.longitude
self.latLong = String(describing: lat!) + "," + String(describing: lon!)
}else{
//handle no adress
self.latLong = ""
}
}
}
回答1:
The problem is that geocodeAddressString runs asynchronously (i.e. it takes so long they have written it to return immediately and call its closure later, when the request is done), so viewDidLoad is printing latLong well before this property was eventually set in the geocodeAddressString completion handler closure.
The solution is to adopt asynchronous programming pattern in your own code. For example, employ your own completion handler pattern:
override func viewDidLoad() {
super.viewDidLoad()
findCordiante(adress: "Cupertino, California, U.S.") { string in
// use `string` here ...
if let string = string {
self.latLong = string
print(string)
} else {
print("not found")
}
}
// ... but not here, because the above runs asynchronously and it has not yet been set
}
func findCordiante(adress:String, completionHandler: @escaping (String?) -> Void) {
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(adress) { placemarks, error in
if let location = placemarks?.first?.location, location.horizontalAccuracy >= 0 {
completionHandler("\(location.coordinate.latitude), \(location.coordinate.longitude)")
} else {
completionHandler(nil)
}
}
}
回答2:
The latLong is nil because print(latLong) is called immediately after the view is loaded, before the value of latLong is set. You can define a function to handle the latLong and call it in the closure.
import UIKit
import CoreLocation
import Firebase
var latLong: String!
override func viewDidLoad() {
super.viewDidLoad()
findCordiante(adress: "Cupertino, California, U.S.")
print(latLong)
}
func findCordiante(adress:String){
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(adress) {
placemarks, error in
if (placemarks != nil){
let placemark = placemarks?.first
let lat = placemark?.location?.coordinate.latitude
let lon = placemark?.location?.coordinate.longitude
self.latLong = String(describing: lat!) + "," + String(describing: lon!)
//Do something with latLong now
self.doSomething(withlatLong: self.latLong)
}else{
//handle no adress
self.latLong = ""
}
}
}
private func doSomething(withlatLong latLong:String) {
//Do whatever you want with latLong
print(latLong)
}
来源:https://stackoverflow.com/questions/47960268/add-value-to-variable-inside-closure-in-swift