Add value to variable inside closure in swift

丶灬走出姿态 提交于 2019-12-08 09:56:29

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!