Swift 如何在闭包中调用func
在模型的classSwift 如何在闭包中调用func,swift,block,cllocation,completionhandler,Swift,Block,Cllocation,Completionhandler,在模型的classLocation中,我得到了当前城市的名称: var currentLatitude: Double! var currentLongitude: Double! var currentLocation: String! var currentCity: String! func getLocationName() { let geoCoder = CLGeocoder() let location = CLLocation(latitude: curren
Location
中,我得到了当前城市的名称:
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()
})
}
在view controller中,我想更新UI并更新标签以显示当前城市。
但是,self.currentCity=city
发生在闭包内部。因此,如果我只是在视图控制器中运行func:
func updateUI() {
cityLbl.text = Location.sharedInstance.currentCity
}
- 我哪儿也去不了,因为关闭还没有结束。
有人建议我在
中添加一个完成处理程序,并在其中执行对func的调用,该函数将更新UI。 然而,从所有关于闭包、完成处理程序的教程中,我不清楚如何实现这一点。 如何构造完成处理程序,将其作为参数传递给getLocationName()
,以及如何从视图控制器调用getLocationName()
李>getLocationName
委托/协议
- 创建一个协议,并使用
实现该协议方法,并在ViewController
类中声明其实例。然后在位置
的reversegeocodocation
中调用此委托方法。有关更多详细信息,请查看上的Apple文档completionHandler
Location
类的getLocationName
方法创建completionHandler
。
- 用
添加getLocationName
,并在completionHandler
的reverseGeocodeLocation
中这样调用该completionHandler
completionHandler
现在,在调用此函数的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)通知中心添加观察员
- 向
注册观察者,然后在(NS)NotificationCenter
的ReverseGeoDelocation
中发布通知。你可以通过这个得到更多的细节completionHandler
您的整个代码:
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位于后台队列中,但您必须始终从主队列中执行与UI相关的操作,以便用户能够以最快的速度更改其UI,而不会出现任何故障。想象一下,如果您在后台线程上执行此操作,并且执行速度很慢,但updateUI()是一个func from view controller,其中声明了位置标签。我应该创建视图控制器的实例并调用func吗?@Mr_Vlasov我明白了,不,你不应该这样做。你应该按照Nirav D的建议去做。如果你有任何疑问,请随意提问。是的,我还不擅长编程,你能展示你提供的第二个选项的实现吗?(假设updateUI()是视图控制器中的一个方法,而不是在实现getLocationName的位置中。)@Mr_Vlasov,所以您希望将completionHandler
与方法一起使用。你在使用Swift 3吗?我正在努力寻找一个关于完成处理程序的好教程或简单解释。Apple文档在介绍闭包的文章中包含了所有不必要的中间人员。你能为闭包理论提供一些好的来源吗?试图掌握它的用法逻辑,而不是语法。@Vlasov先生检查这个和这个
// 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
}
})
}