Закрытие манипуляции в Swift
Я новичок в Swift и не могу понять, как обращаться с замыканиями и замыканиями.
Я недавно задал вопрос, и я узнаю, что моя переменная равна нулю, потому что geocodeAddressString
работает асинхронно, поэтому печать приложения latLong
задолго до того, как это свойство было в конечном итоге установлено.
Но вот новый вопрос, который я не могу понять:
import UIKit
import CoreLocation
import Firebase
var latLong: String!
override func viewDidLoad() {
super.viewDidLoad()
}
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 = ""
}
}
}
@IBAction func createSchool(_ sender: Any) {
//when user press button i want execute function and assign value to variable latLong
findCordiante(adress: "Cupertino, California, U.S.")
//so then I need to manipulate with that value here, let's say example
//example
print("Hi user, your coordinates is \(latLong)")
}
Когда я добавлю print(latLong)
внутри закрытия это печать, но я не хочу делать все функции внутри закрытия.
Просто ХОЧУ добавить результат func findCordiante()
к переменной latLong
так что после этого я могу манипулировать этой переменной везде внутри класса
3 ответа
Главное, что нужно понять, это то, что преобразование адреса в координаты (и многие другие операции геолокации) требует времени и, следовательно, возвращает результат со значительной задержкой. Во время задержки приложение продолжает работать и должно реагировать на действия пользователя.
Вот почему используются замыкания, а именно, чтобы разделить операцию на две части:
- Начните операцию (ваш
findCoordinate
функция) - Завершить действие после завершения операции (замыкание, используется как обратный вызов)
Между этими двумя частями ваше приложение работает нормально. Это не ждет и не блокирует. Если вам нужно поведение ожидания, вы должны реализовать его самостоятельно (например, отключить кнопки, игнорировать жесты пользователя и т. Д. (.
Вы можете легко переместить часть кода внутри замыкания в отдельную функцию:
func findCordiante(adress:String){
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(adress) {
placemarks, error in
if let placemarks = placemarks {
self.findCoordinateCompleted(placemarks)
} else {
self.findCoordinateFailed()
}
}
}
func findCoordinateCompleted(placemarks: [CLPlacemark]) {
let placemark = placemarks.first!
let lat = placemark.location!.coordinate.latitude
let lon = placemark.location!.coordinate.longitude
latLong = String(describing: lat) + "," + String(describing: lon)
completeCreatingSchool()
}
func findCoordinateFailed() {
latLong = ""
print("Hi user, invalid address")
// do more stuff here
}
@IBAction func createSchool(_ sender: Any) {
findCoordinate(adress: "Cupertino, California, U.S.")
}
func completeCreatingSchool() {
//example
print("Hi user, your coordinates is \(latLong)")
}
В соответствии с вашим кодом самое близкое решение - использовать обработчик завершения и вернуть логическое значение success
в закрытии. Тогда вы можете использовать latLong
переменная (не будет CLLocationCoordinate2D
лучше типа?) сразу после установки.
func findCoordinate(adress:String, completion: @escaping (Bool)->()){
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!)
completion(true)
}else{
//handle no adress
self.latLong = ""
completion(false)
}
}
}
@IBAction func createSchool(_ sender: Any) {
//when user press button i want execute function and assign value to variable latLong
findCoordinate(adress: "Cupertino, California, U.S.") { success in
//so then I need to manipulate with that value here, let's say example
//example
if success {
print("Hi user, your coordinates is \(latLong)")
}
}
}
После того, как вы установили latLong
в закрытии, это будет доступно для остальной части вашего класса. Единственная проблема у вас есть, если createSchool
вызывается до завершения закрытия.
Решение этой проблемы состоит в том, чтобы иметь кнопку и / или пункт меню, который указывает на createSchool
начало отключено. Затем вы включаете его после завершения закрытия.