异步地理定位 Return

Asynchronous GeoLocation Return

使用 locationManager 的坐标,我想在底部显示通过反向 geoLocation 获得的位置(地址)的地图。坐标和地图显示正确,但我无法生成地址。我正在尝试遵循 iOS 11 或更高版本 部分中 处的示例代码。示例中显示的两个扩展(CLPlacemark 和 CLLocation)与我使用的相同。所以看起来,虽然我遵循示例用法,但我没有正确处理异步 Placemark 函数。函数 getLocation() 正确显示地址,但它没有返回到 saveButton()。

任何有关异步函数的帮助 return 将不胜感激。

struct EntryView: View {
    @Environment(\.managedObjectContext) var viewContext    // core data
    @ObservedObject private var lm = LocationManager()      // location

    @State private var entryLat: Double = 0.0
    @State private var entryLong: Double = 0.0
    @State private var addr: String = ""
    
    var body: some View {
        
        GeometryReader { g in
            
            List {  

              Button(action: {
                    self.saveButton()   // save entry button pressed
                }) {
                    HStack {
                        Spacer()
                        Text ("Save")
                        Spacer()
                    }
                }
        }
        .navigationBarHidden(true)
        .navigationViewStyle(StackNavigationViewStyle())
    }

    // the save button has been pressed
    func saveButton() {
        
        // get coordinates and address
        let addr = getLocation()
        print("addr = \(addr)")  // nothing displayed here except addr
        
        // save entry to core data
        let newEntry = CurrTrans(context: viewContext)
        
        newEntry.id = UUID()                            
        newEntry.entryDT = entryDT         // entry date
        newEntry.entryDsc = entryDsc       // entry description                      
        newEntry.moneyD = moneyD           // money as double
        
        newEntry.entryLat = entryLat       // store location for maps
        newEntry.entryLong = entryLong
        
        newEntry.address = addr           // formatted address
        print("newEntry.address = \(newEntry.address ?? "")")  
        
        do {
            try viewContext.save()
            
        } catch {
            print(error.localizedDescription)
        }
    }

    func getLocation() -> String {
 
        // get location coordinates
        let result = lm.getLocationCoordinates()
        entryLat = result.0
        entryLong = result.1
        
        // get location address
        let location = CLLocation(latitude: entryLat, longitude: entryLong)
        location.placemark { placemark, error in
            guard let placemark = placemark else {
                print("Error:", error ?? "nil")
                return
            }
            
            print("formatted address: \(placemark.postalAddressFormatted ?? "")")
            addr = placemark.postalAddressFormatted ?? "Unknown"
            return addr
        }
    }
}

下面的代码是位置管理器的一部分。

extension CLLocation {
    func placemark(completion: @escaping (_ placemark: CLPlacemark?, _ error: Error?) -> ()) {
        CLGeocoder().reverseGeocodeLocation(self) { completion([=12=]?.first, ) }
    }
}

extension CLPlacemark {
    /// street name, eg. Infinite Loop
    var streetName: String? { thoroughfare }
    /// // eg. 1
    var streetNumber: String? { subThoroughfare }
    /// city, eg. Cupertino
    var city: String? { locality }
    /// neighborhood, common name, eg. Mission District
    var neighborhood: String? { subLocality }
    /// state, eg. CA
    var state: String? { administrativeArea }
    /// county, eg. Santa Clara
    var county: String? { subAdministrativeArea }
    /// zip code, eg. 95014
    var zipCode: String? { postalCode }
    /// postal address formatted
   
    var postalAddressFormatted: String? {
        guard let postalAddress = postalAddress else { return nil }
        return CNPostalAddressFormatter().string(from: postalAddress)
    }
}

您的代码无法编译。当您尝试 return addr` 时,编译器会发出有关 Unexpected non-void return value in void function 的警告,因为闭包具有非空 return 类型。

而是使用完成处理程序。

这可能看起来像这样:

func getLocation(completion: @escaping (String) -> Void) {
    // get location coordinates
    let result = lm.getLocationCoordinates()
    entryLat = result.0
    entryLong = result.1
    
    // get location address
    let location = CLLocation(latitude: entryLat, longitude: entryLong)
    location.placemark { placemark, error in
        guard let placemark = placemark else {
            print("Error:", error ?? "nil")
            return
        }
        
        print("formatted address: \(placemark.postalAddressFormatted ?? "")")
        addr = placemark.postalAddressFormatted ?? "Unknown"
        completion(addr)
    }
}

而且,早些时候,在 saveButton 中:

func saveButton() {
    
    // get coordinates and address
    getLocation { addr in
        print("addr = \(addr)")
        self.addr = addr
        //do your CoreData code that depends on addr here
    }
    //don't try to use addr here, outside the completion handler
}

您的 body

中还缺少 }