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)
}