等待 google 反向地理编码
Wait for google reverse geocoding
我是 swift 的新手。对于我的项目,我需要使用 google 地理编码并将结果放入文本中。对于用户界面,我使用 swiftUI。我尝试对 Completition Handler 做同样的事情,但没有用。下面我用 DispatchQueue 和 DispatchGroup 完成了代码,但是当我尝试使用这个 func 时整个应用程序冻结了。请帮我解决一下这个。 UI 的代码只是调用函数的文本。
func reverseGeocoding(lat: Double, lng: Double) -> String{
var place:String?
let url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(lat),\(lng)&key=KEY"
let group = DispatchGroup()
group.enter()
DispatchQueue.global(qos: .default).async {
AF.request(url).responseJSON{ response in
// group.leave()
guard let data = response.data else {
return
}
do {
let jsonData = try JSON(data: data)
let result = jsonData["results"].arrayValue
for result in result {
let address_components = result["types"].arrayValue
for component in address_components {
if(component == "locality"){
place = result["formatted_address"].stringValue
}
}
}
} catch let error {
print(error.localizedDescription)
}
}
}
group.wait()
return place ?? ""
}
你需要一个这样的完成处理程序,它returns还有Result
类型
中的所有错误
enum GeoError : Error {
case locationNoFound
}
func reverseGeocoding(lat: Double, lng: Double, completion: @escaping (Result<String,Error>) -> Void) {
let url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(lat),\(lng)&key=KEY"
DispatchQueue.global(qos: .default).async {
AF.request(url).responseData { response in
switch response.result {
case .success(let data):
do {
let jsonData = try JSON(data: data)
let result = jsonData["results"].arrayValue
for result in result {
let addressComponents = result["types"].arrayValue
for component in addressComponents {
if component == "locality" {
completion(.success(result["formatted_address"].stringValue))
}
}
}
completion(.failure(GeoError.locationNoFound))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
并使用它
reverseGeocoding(lat: 45.0, lng: 45.0) { result in
switch result {
case .success(let location): print(location)
case .failure(let error): print(error)
}
}
继续@vadian 的回答
正如上面提到的发布者取决于上下文。这会给你一个粗略的 idea.This 是从我的理解..
// Replace String with [String] if you want to add multiple locations at once based on it Publisher.send() accepts [String] instead of String
var LocationPublisher = PassthroughSubject<String,Never>()
class Subscriber :ObservableObject {
@Published var currentLocation :[String] = Array<String>()
private var cancellebels = Set< AnyCancellable>()
func createSubscriber(){
let subscriber = LocationPublisher.handleEvents(
receiveSubscription: {subscription in
print("New subscription \(subscription)")},
receiveOutput: {output in
print("New Output \(output)")
},
receiveCancel: {
print("Subscription Canceled")
})
.receive(on: RunLoop.main)
// if you replace String with [String],TypeOf(value) becomes [String]
.sink{value in
print("Subscriber recieved value \(value)")
self.currentLocation.append(value)
// use self.currenLocation.append(contentsOf:value) instead
}
.store(in: &cancellebels)
}
init() {
createSubscriber()
}
}
在这个 contentView 里面
struct ContentView: View {
@ObservedObject var locationObject:Subscriber = Subscriber()
var body: some View {
VStack{
List{
locationObject.currentLocation.forEach{ location in
Text(location)
}
}
}
}
}
并从上面的成功完成处理程序中的答案中使用
LocationPublisher.send(location)
而不是打印语句
它将通知订阅者并且 locationObject.currentLocation 将被更新
这只是一种方法,也是最基本的方法。
我是 swift 的新手。对于我的项目,我需要使用 google 地理编码并将结果放入文本中。对于用户界面,我使用 swiftUI。我尝试对 Completition Handler 做同样的事情,但没有用。下面我用 DispatchQueue 和 DispatchGroup 完成了代码,但是当我尝试使用这个 func 时整个应用程序冻结了。请帮我解决一下这个。 UI 的代码只是调用函数的文本。
func reverseGeocoding(lat: Double, lng: Double) -> String{
var place:String?
let url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(lat),\(lng)&key=KEY"
let group = DispatchGroup()
group.enter()
DispatchQueue.global(qos: .default).async {
AF.request(url).responseJSON{ response in
// group.leave()
guard let data = response.data else {
return
}
do {
let jsonData = try JSON(data: data)
let result = jsonData["results"].arrayValue
for result in result {
let address_components = result["types"].arrayValue
for component in address_components {
if(component == "locality"){
place = result["formatted_address"].stringValue
}
}
}
} catch let error {
print(error.localizedDescription)
}
}
}
group.wait()
return place ?? ""
}
你需要一个这样的完成处理程序,它returns还有Result
类型
enum GeoError : Error {
case locationNoFound
}
func reverseGeocoding(lat: Double, lng: Double, completion: @escaping (Result<String,Error>) -> Void) {
let url = "https://maps.googleapis.com/maps/api/geocode/json?latlng=\(lat),\(lng)&key=KEY"
DispatchQueue.global(qos: .default).async {
AF.request(url).responseData { response in
switch response.result {
case .success(let data):
do {
let jsonData = try JSON(data: data)
let result = jsonData["results"].arrayValue
for result in result {
let addressComponents = result["types"].arrayValue
for component in addressComponents {
if component == "locality" {
completion(.success(result["formatted_address"].stringValue))
}
}
}
completion(.failure(GeoError.locationNoFound))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}
}
并使用它
reverseGeocoding(lat: 45.0, lng: 45.0) { result in
switch result {
case .success(let location): print(location)
case .failure(let error): print(error)
}
}
继续@vadian 的回答
正如上面提到的发布者取决于上下文。这会给你一个粗略的 idea.This 是从我的理解..
// Replace String with [String] if you want to add multiple locations at once based on it Publisher.send() accepts [String] instead of String
var LocationPublisher = PassthroughSubject<String,Never>()
class Subscriber :ObservableObject {
@Published var currentLocation :[String] = Array<String>()
private var cancellebels = Set< AnyCancellable>()
func createSubscriber(){
let subscriber = LocationPublisher.handleEvents(
receiveSubscription: {subscription in
print("New subscription \(subscription)")},
receiveOutput: {output in
print("New Output \(output)")
},
receiveCancel: {
print("Subscription Canceled")
})
.receive(on: RunLoop.main)
// if you replace String with [String],TypeOf(value) becomes [String]
.sink{value in
print("Subscriber recieved value \(value)")
self.currentLocation.append(value)
// use self.currenLocation.append(contentsOf:value) instead
}
.store(in: &cancellebels)
}
init() {
createSubscriber()
}
}
在这个 contentView 里面
struct ContentView: View {
@ObservedObject var locationObject:Subscriber = Subscriber()
var body: some View {
VStack{
List{
locationObject.currentLocation.forEach{ location in
Text(location)
}
}
}
}
}
并从上面的成功完成处理程序中的答案中使用
LocationPublisher.send(location)
而不是打印语句
它将通知订阅者并且 locationObject.currentLocation 将被更新
这只是一种方法,也是最基本的方法。