gpt4 book ai didi

swift - 我在 Swift 中对地址(罕见)进行地理编码时出错

转载 作者:行者123 更新时间:2023-12-03 09:25:42 30 4
gpt4 key购买 nike

我有一个 SearchBar,它更新某个 Binding 字符串,该字符串是地理编码的潜在位置匹配列表。有时,当我输入一个位置时,我会得到以下信息:

libswiftCore.dylib`_swift_runtime_on_report:
-> 0x1054f7180 <+0>: pushq %rbp //Error on this line says "= Thread 1: Fatal Error: Duplicate keys
of type 'GeocodedPlacemark' were found in a Dictionary. This usually means either that the type
violates Hashable's requirements, or that members of the dictionary were mutated after
insertion."
0x1054f7181 <+1>: movq %rsp, %rbp
0x1054f7184 <+4>: popq %rbp
0x1054f7185 <+5>: retq
0x1054f7186 <+6>: nopw %cs:(%rax,%rax)

唯一的问题是,它让我不知道错误的来源在哪里......所有这些数字中是否有一些线索或在那行找到的“pushq”关键字可以将我引导到它所指的字典?

旁注:此错误可能在每 15 次左右的搜索中发生一次,因此非常罕见。

搜索条码如下:
import SwiftUI
import Mapbox
import MapboxGeocoder

struct SearchBar: View {


var annotation: AnnotationsVM
@State var searchText: String = ""
//@State var typing: Bool = false
@State private var showCancelButton: Bool = false
@ObservedObject var locationManager = LocationManager()
@ObservedObject var VModel : ViewModel
@Binding var searchedText: String
@Binding var showResults: Bool
@Binding var showMoreDetails: Bool
var mapStyle: URL

var body: some View {

let binding = Binding<String>(get: {
self.searchText
}, set: {
self.searchText = $0
self.searchedText = self.searchText
self.VModel.findResults(address: self.searchedText)
if self.VModel.searchResults.count >= 0 {
self.showResults = true
self.showMoreDetails = false
} else {
self.showResults = false
}
}
)


return VStack {
// Search view
HStack {
Image(systemName: "magnifyingglass")

TextField("search", text: binding, onEditingChanged: { isEditing in
self.showCancelButton = true
self.showMoreDetails = false

}, onCommit: {
if self.VModel.searchResults.first != nil {
self.annotation.addNextAnnotation(address: self.rowText(result: self.VModel.searchResults.first!).label)
self.searchedText = "\(self.rowText(result: self.VModel.searchResults.first!).label)"
}
self.showMoreDetails = false
self.showResults = false
})

Button(action: {
self.searchText = ""
self.showResults = false
}) {
Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0.0 : 1.0)
}
}
.padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
}

if showCancelButton {
Button("Cancel") {
UIApplication.shared.endEditing(true) // this must be placed before the other commands here
self.searchText = ""
self.showResults = false
self.showCancelButton = false
}

}
.padding(.horizontal)
}
}



private func rowText(result: GeocodedPlacemark) -> (view: Text, label: String) {


// city is not nil
// state is not nil
// country is not nil
if result.postalAddress != nil && result.postalAddress?.city != "" && result.postalAddress?.state != "" && result.postalAddress?.country != "" {

return (Text("\(result.formattedName), \(result.postalAddress!.city), \(result.postalAddress!.state), \(result.postalAddress!.country)"), "\(result.formattedName), \(result.postalAddress!.city), \(result.postalAddress!.state), \(result.postalAddress!.country)")
}



// city is not nil
// state is not nil
// country is nil
else if result.postalAddress != nil && result.postalAddress?.city != "" && result.postalAddress?.state != "" && result.postalAddress?.country == "" {

return (Text("\(result.formattedName), \(result.postalAddress!.city), \(result.postalAddress!.state)"), "\(result.formattedName), \(result.postalAddress!.city), \(result.postalAddress!.state)")
}


// city is not nil
// state is nil
// country is nil
else if result.postalAddress != nil && result.postalAddress?.city != "" && result.postalAddress?.state == "" && result.postalAddress?.country == "" {

return (Text("\(result.formattedName), \(result.postalAddress!.city)"), "\(result.formattedName), \(result.postalAddress!.city)")

}

//More if statements to cover all the different states, this section essentially just returns the way to format the different search results in the search results view (that results view works fine btw)

}


extension UIApplication {
func endEditing(_ force: Bool) {
self.windows
.filter{$0.isKeyWindow}
.first?
.endEditing(force)
}
}

struct ResignKeyboardOnDragGesture: ViewModifier {
var gesture = DragGesture().onChanged{_ in
UIApplication.shared.endEditing(true)
}
func body(content: Content) -> some View {
content.gesture(gesture)
}
}

extension View {
func resignKeyboardOnDragGesture() -> some View {
return modifier(ResignKeyboardOnDragGesture())
}
}

VModel 类如下:
class ViewModel: ObservableObject {

@ObservedObject var locationManager = LocationManager()
@Published var lat: Double?
@Published var lon: Double?
@Published var location: CLLocationCoordinate2D?
@Published var name: CLPlacemark?
@Published var searchResults: [GeocodedPlacemark] = []


var userLatitude: CLLocationDegrees {
return (locationManager.lastLocation?.latitude ?? 0)
}

var userLongitude: CLLocationDegrees {
return (locationManager.lastLocation?.longitude ?? 0)
}






func getLocation(from address: String, completion: @escaping (_ location: CLLocationCoordinate2D?)-> Void) {
//let geocoder = CLGeocoder()
let geocoder = Geocoder(accessToken: "pk.eyJ1Ijoibmlja2JyaW5zbWFkZSIsImEiOiJjazh4Y2dzcW4wbnJyM2ZtY2V1d20yOW4wIn0.LY1H3cf7Uz4BhAUz6JmMww")
let foptions = ForwardGeocodeOptions(query: address)
print("hit this point")
foptions.focalLocation = CLLocation(latitude: userLatitude, longitude: userLongitude)
geocoder.geocode(foptions) { (placemarks, attribution ,error) in
guard let placemarks = placemarks,
let location = placemarks.first?.location?.coordinate
else {
completion(nil)
return
}
completion(location)
}
}




func fetchCoords(address: String, completion: @escaping (Double, Double) -> Void){
self.getLocation(from: address) { coordinates in
print(coordinates ?? 0) // Print here
self.location = coordinates // Assign to a local variable for further processing
if let lat = coordinates?.latitude, let lon = coordinates?.longitude {
completion(lat, lon)
}
}
}






func findResults(address: String) {
let geocoder = Geocoder(accessToken: "pk.eyJ1Ijoibmlja2JyaW5zbWFkZSIsImEiOiJjazh4Y2dzcW4wbnJyM2ZtY2V1d20yOW4wIn0.LY1H3cf7Uz4BhAUz6JmMww")
let foptions = ForwardGeocodeOptions(query: address)
foptions.focalLocation = CLLocation(latitude: userLatitude, longitude: userLongitude)
foptions.maximumResultCount = 10
geocoder.geocode(foptions) { (placemarks, attribution ,error) in
guard let placemarks = placemarks
else {
return
}
self.searchResults = []
for placemark in placemarks {
self.searchResults.append(placemark)
}
}
}
}

设置了一个Swift Error Breakpoint后,就停止了在这个函数中的搜索(我猜这是一个后端的MapBox函数,因为肯定不是我写的;可能是框架自带的?):
fileprivate func dataTaskWithURL(_ url: URL, completionHandler: @escaping (_ data: Data?) -> Void, errorHandler: @escaping (_ error: NSError) -> Void) -> URLSessionDataTask {
var request = URLRequest(url: url)

request.setValue(userAgent, forHTTPHeaderField: "User-Agent")
return URLSession.shared.dataTask(with: request) { (data, response, error) in

guard let data = data else {
DispatchQueue.main.async {
if let e = error as NSError? {
errorHandler(e)
} else {
let unexpectedError = NSError(domain: MBGeocoderErrorDomain, code: -1024, userInfo: [NSLocalizedDescriptionKey : "unexpected error", NSDebugDescriptionErrorKey : "this error happens when data task return nil data and nil error, which typically is not possible"])
errorHandler(unexpectedError)
}
}
return
}
let decoder = JSONDecoder()

do {
// Handle multiple batch geocoding queries, THE ERROR IS ON THE LINE BELOW and says 'Thread 19: breakpoint 1.1'
let result = try decoder.decode([GeocodeAPIResult].self, from: data)

// Check if any of the batch geocoding queries failed
if let failedResult = result.first(where: { $0.message != nil }) {
let apiError = Geocoder.descriptiveError(["message": failedResult.message!], response: response, underlyingError: error as NSError?)
DispatchQueue.main.async {
errorHandler(apiError)
}
return
}
DispatchQueue.main.async {
completionHandler(data)
}
} catch {
// Handle single & single batch geocoding queries
do {
let result = try decoder.decode(GeocodeAPIResult.self, from: data)
// Check if geocoding query failed
if let message = result.message {
let apiError = Geocoder.descriptiveError(["message": message], response: response, underlyingError: error as NSError?)
DispatchQueue.main.async {
errorHandler(apiError)
}
return

}
DispatchQueue.main.async {
completionHandler(data)
}
} catch {
// Handle errors that don't return a message (such as a server/network error)
DispatchQueue.main.async {
errorHandler(error as NSError)
}
}
}
}
}

最佳答案

建议先更新iOS MapboxMapBox Geocoder SDK 到最新版本 - 有时这些更新会修复框架中的突出错误。

接下来,我建议包装导致错误的 geocode同步线路 DispatchQueue块,像这样:

func getLocation(from address: String, completion: @escaping (_ location: CLLocationCoordinate2D?)-> Void) {
//let geocoder = CLGeocoder()
let geocoder = Geocoder(accessToken: "pk.eyJ1Ijoibmlja2JyaW5zbWFkZSIsImEiOiJjazh4Y2dzcW4wbnJyM2ZtY2V1d20yOW4wIn0.LY1H3cf7Uz4BhAUz6JmMww")
let foptions = ForwardGeocodeOptions(query: address)
print("hit this point")
foptions.focalLocation = CLLocation(latitude: userLatitude, longitude: userLongitude)
DispatchQueue.global().sync {
geocoder.geocode(foptions) { (placemarks, attribution ,error) in
guard let placemarks = placemarks,
let location = placemarks.first?.location?.coordinate
else {
completion(nil)
return
}
completion(location)
}
}
}

func findResults(address: String) {
let geocoder = Geocoder(accessToken: "pk.eyJ1Ijoibmlja2JyaW5zbWFkZSIsImEiOiJjazh4Y2dzcW4wbnJyM2ZtY2V1d20yOW4wIn0.LY1H3cf7Uz4BhAUz6JmMww")
let foptions = ForwardGeocodeOptions(query: address)
foptions.focalLocation = CLLocation(latitude: userLatitude, longitude: userLongitude)
foptions.maximumResultCount = 10
DispatchQueue.global().sync {
geocoder.geocode(foptions) { (placemarks, attribution ,error) in
guard let placemarks = placemarks else {
return
}
self.searchResults = []
for placemark in placemarks {
self.searchResults.append(placemark)
}
}
}
}

如果这不能解决问题,那么我建议在引发 Swift 错误断点时在 Xcode 中查看堆栈帧中的各个线程 - 您可以通过点击不同的线程名称在左侧面板上执行此操作。看到这个:

如何选择线程:
select different thread

一旦您可以看到每个线程的单独代码行(点击左侧的每个线程,显示每个文件的代码),您可以添加相同的 DispatchQueue.global().sync { }为每个相关线程阻塞代码中冲突的访问行。我现在概述了如何选择放置这些块的位置。

如果您在图像中看到,对于每个线程,调用堆栈从下到上列出。您只需要添加 DispatchQueue.global().sync { }堵在 data 所在的一行附近正在访问变量。但是,如果您正在访问 data完成块内的变量(如您的地理编码函数)然后是 DispatchQueue.global().sync { }需要遍历整个函数。

如何在 Thread 1中选择错误行:
error line selection

希望这可以帮助! :)

关于swift - 我在 Swift 中对地址(罕见)进行地理编码时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62139410/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com