Home > database >  Cannot pass function of type '([CLPlacemark]?, (any Error)?) async throws -> Void' to p
Cannot pass function of type '([CLPlacemark]?, (any Error)?) async throws -> Void' to p

Time:11-04

I have written this code:

In the first step, I read an Excel file that contains the addresses of the buildings as a string.

LABE HAUS Gemeindename
Hasenwinkel 14 Braunschweig

The Excel file is similar to the table above.

I want to read the addresses inside a loop and get the coordinates of the addresses (Lat, Long) using CLGeocoder. Using the snapshotImage function, I give the coordinates as input to the function, and if there is picture, I want to save that picture of the target address with its address name.

But I get the following errors:

1.Cannot pass function of type '([CLPlacemark]?, (any Error)?) async throws -> Void' to parameter expecting synchronous function type

2. Invalid conversion from throwing function of type '([CLPlacemark]?, (any Error)?) async throws -> Void' to non-throwing function type '([CLPlacemark]?, (any Error)?) -> Void'

let columnTypes: [String: CSVType] = ["LABE": .string,
                                      "HAUS": .string,
                                      "Gemeindename": .string]


let path = Bundle.main.url(forResource: "Adresse", withExtension: "csv")!
let options = CSVReadingOptions(
    hasHeaderRow: true,
    ignoresEmptyLines: true,
    delimiter: ";"
    )



let result = try DataFrame(contentsOfCSVFile: path,rows: 0..<50, types: columnTypes,options: options)


enum LookaroundError: Error {
    case unableToCreateScene
}

func snapshotImage(for coordinate: CLLocationCoordinate2D) async throws -> UIImage {
    guard let scene = try await MKLookAroundSceneRequest(coordinate: coordinate).scene else {
        throw LookaroundError.unableToCreateScene
    }
    let options = MKLookAroundSnapshotter.Options()
    options.size = CGSize(width: 1000, height: 500)
    return try await MKLookAroundSnapshotter(scene: scene, options: options).snapshot.image
}

var address: String = ""


for row in result.rows {
    if row["HAUS"] == nil {
        
        address = "\(row["LABE"] ?? <#default value#>) \(row["Gemeindename"] ?? <#default value#>)"
        
    } else {

        address = "\(row["LABE"] ?? <#default value#>) \(row["HAUS"] ?? <#default value#>) \(row["Gemeindename"] ?? <#default value#>)"
    }
    
    print(address)
    
    let geocoder = CLGeocoder()
    geocoder.geocodeAddressString(address){ (placemarks, error) in
        guard
            let placemarks = placemarks,
            let location: CLLocationCoordinate2D = placemarks.first?.location?.coordinate
        else{
            return
        }
        
        var image = try await snapshotImage(for: location)
        var url = try FileManager.default
            .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            .appending(component: "\(address).png")
        try image.pngData()?.write(to: url)
    }
    
}

Ideally, I want to read the addresses in this loop and save a picture of them using their coordinates.I don't have much experience in Swift programming. Does anyone have an idea how to solve the code problem?

CodePudding user response:

The error tells you exactly what's wrong, but it may not be obvious why it is wrong.

This line

var image = try await snapshotImage(for: location)

makes the closure you pass to geocoder.geocodeAddressString asynchronous. That function will not accept async closures. It's not declared to. It's the same as if you passed a throwing closure to a non throwing parameter.

Since you don't provide the definition for geocoder.geocodeAddressString it is difficult to suggest a fix. Perhaps just build an array of locations in the loop and then get the snapshot images afterwards.

CodePudding user response:

change

geocoder.geocodeAddressString(address){ (placemarks, error) in
        guard
            let placemarks = placemarks,
            let location: CLLocationCoordinate2D = placemarks.first?.location?.coordinate
        else{
            return
        }

to

guard let location = try await geocoder.geocodeAddressString(address).first?.location?.coordinate else { return }

or, more correct, mark your function signature with throws and

do {
    let location = try await geocoder.geocodeAddressString(address).first?.location?.coordinate
} catch {
    throw(error)
}
  • Related