在模型的课程#rust
中,我得到当前城市的名称:
Location
在视图控制器中,我想更新UI并更新我的标签以显示当前城市。
但是,var currentLatitude: Double!
var currentLongitude: Double!
var currentLocation: String!
var currentCity: String!
func getLocationName() {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
self.nowUpdateUI()
})
}
发生在闭包内部。所以如果我只是在视图控制器中运行一个func:
self.currentCity = city
func updateUI() {
cityLbl.text = Location.sharedInstance.currentCity
}
添加一个完成处理程序,在其中,执行对将更新UI的func的调用。
但是,从闭包,完成处理程序的所有教程中,我不清楚如何实现这一点。
如何构造一个完成处理程序,将其作为arg传递给getLocationName()
以及如何从视图控制器调用getLocationName()
? 答案 0 :(得分:2)
要处理这种情况,您有多种选择。
使用您的位置等级
创建delegate/protocol
ViewController
实现该协议方法,并在Location
类中声明其实例。然后在completionHandler
reverseGeocodeLocation
中调用此委托方法。有关详细信息,请查看Protocol
上的Apple文档。 您可以使用[{1}}类completionHandler
方法创建getLocationName
。
使用Location
添加completionHandler
,并以getLocationName
completionHandler
的方式将completionHandler
称为reverseGeocodeLocation
。
func getLocationName(completionHandler: @escaping (_ success: Bool) -> Void) {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
completionHandler(false)
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
completionHandler(true)
//self.nowUpdateUI()
})
}
现在在ViewController
调用此函数的地方,请在完成块内调用updateUI
方法。
Location.sharedInstance.getLocationName { (success) in
if success {//If successfully got response
self.updateUI()
}
}
您可以为(NS)NotificationCenter
添加观察者。
(NS)NotificationCenter
注册观察者,然后将通知发布在completionHandler
的{{1}}内。您可以使用此StackOverflow Post。答案 1 :(得分:0)
这整段代码:
completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
self.nowUpdateUI()
}
)
已经在completionHandler中发生(在完成所有操作后都会发生)还要在completionHandler中运行updateUI()
。所以你的最终代码是:
completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
DispatchQueue.main.async {
updateUI()
}
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
self.nowUpdateUI()
}
)
你必须使用DispatchQueue.main
的原因是因为你的completionHandler是在backgroundqueue上的,但是你必须总是从你的mainQueue做与UI相关的东西 - 所以用户在他们的UI中获得最快的变化而没有任何故障。想象一下,如果你在后台线程上做的事情发生得很慢
答案 2 :(得分:0)
// I thing issue back ground thread you need to update your UI in main thread
var currentLatitude: Double!
var currentLongitude: Double!
var currentLocation: String!
var currentCity: String!
func getLocationName() {
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
return
}
if let city = addressDict["City"] as? String {
self.currentCity = city
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
DispatchQueue.main.async {
self.nowUpdateUI()
// Update your UI in main thread
}
})
}