CLPlacemark has no member 'get' - ios

I am referring one func to get user's location and the code is below:
func updateLocation(_ userLocation: CLLocation) {
if (userLocation.horizontalAccuracy > 0) {
self.locationService.stopUpdatingLocation()
return
}
self.latitude = NSNumber(value: userLocation.coordinate.latitude as Double)
self.longitude = NSNumber(value: userLocation.coordinate.longitude as Double)
if !self.geocoder.isGeocoding {
self.geocoder.reverseGeocodeLocation(userLocation, completionHandler: {(placemarks, error) in
if let error = error {
logger.error("reverse geodcode fail: \(error.localizedDescription)")
return
}
if let placemarks = placemarks, placemarks.count > 0 {
// TODO:
let onePlacemark = placemarks.get(index: 0)
self.address = "\(onePlacemark?.administrativeArea,onePlacemark?.subLocality,onePlacemark?.thoroughfare)"
self.city = (onePlacemark?.administrativeArea!)!
self.street = (onePlacemark?.thoroughfare!)!
}
})
}
}
When building the project, it threw something "CLPlacemark has no member 'get'" at this line:
let onePlacemark = placemarks.get(index: 0)
I am writing the project with swift 4.0, and
import Foundation
import INTULocationManager
is done.

Related

Domain=kCLErrorDomain Code=8 when fetching location through zipcode

I'm trying to fetch the the latitude and longitude based on the input parameters postal/city and country code. Below is my code, this works fine if enter City and country name but shows error if I enter zipcode and country code. Below is the code. (Note: Location services and app permissions are enabled)
func getLocationFrom(postalCityCode: String, countryCode: String) -> CLLocation? {
let geocoder = CLGeocoder()
var location: CLLocation?
let address = CNMutablePostalAddress()
address.postalCode = postalCityCode
address.country = countryCode
geocoder.geocodePostalAddress(address, preferredLocale: Locale.current) { (placemarks, error) in
guard error == nil else {
print("Error: \(error!)")
return
}
guard let placemark = placemarks?.first else {
print("Error: placemark is nil")
return
}
guard let coordinate = placemark.location?.coordinate else {
print("Error: coordinate is nil")
return
}
location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
print("Found location = \(location)")
}
return location
}
Working input: Shanghai, CN
Failing input: 200040, CN
Edit
Attached updated code as suggested in the answer but still experiencing same issue
Currently, you are using return location before it is set, since geocoder.geocodePostalAddress(...) is an asynchronous function.
That means you need to use a completion handler (for example) to return the location, when it has the results, something like this:
func getLocationFrom(postalCityCode: String, countryCode: String, completion: #escaping ( CLLocation?) -> Void) {
let geocoder = CLGeocoder()
var location: CLLocation?
let address = CNMutablePostalAddress()
address.postalCode = postalCityCode
address.country = countryCode
geocoder.geocodePostalAddress(address, preferredLocale: Locale.current) { (placemarks, error) in
guard error == nil else {
print("Error: \(error!)")
return completion(nil)
}
guard let placemark = placemarks?.first else {
print("Error: placemark is nil")
return completion(nil)
}
guard let coordinate = placemark.location?.coordinate else {
print("Error: coordinate is nil")
return completion(nil)
}
location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
print("\n--> Found location = \(location) \n")
completion(location) // <-- here
}
}
Use it like this:
getLocationFrom(postalCityCode: "200040", countryCode: "CN") { location in
print("\n---> location: \(location) \n")
}
EDIT-1
for testing and isolating the issue, try this code in a new SwiftUI project:
struct ContentView: View {
#State var cityLocation = CLLocation()
var body: some View {
Text(cityLocation.description)
.onAppear {
getLocationFrom(postalCityCode: "200040", countryCode: "CN") { location in
print("\n---> location: \(location) \n")
if let theLocation = location {
cityLocation = theLocation
}
}
}
}
func getLocationFrom(postalCityCode: String, countryCode: String, completion: #escaping ( CLLocation?) -> Void) {
let geocoder = CLGeocoder()
var location: CLLocation?
let address = CNMutablePostalAddress()
address.postalCode = postalCityCode
address.country = countryCode
geocoder.geocodePostalAddress(address, preferredLocale: Locale.current) { (placemarks, error) in
guard error == nil else {
print("Error: \(error!)")
return completion(nil)
}
guard let placemark = placemarks?.first else {
print("Error: placemark is nil")
return completion(nil)
}
guard let coordinate = placemark.location?.coordinate else {
print("Error: coordinate is nil")
return completion(nil)
}
location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
print("\n--> Found location = \(location) \n")
completion(location)
}
}
}

forward geocoding completionHandler is not executing in iOS swift4

I am trying convert to addresses into latlongs to place them on googleMap but, when I pass the address String to geoCoder.geoAddressString(fullAddress) and running application, completionHandler is not executing, I tried with breakpoint at geoCoder.geocodeAddressString(fullAddress) { (placemarks, error) and when I click on stepover it is coming out if the completionHandler..
Now, I have no idea why this is happening... Does anyone know? please Help..
see My code Here:
func loadMarkers() {
for i in 0..<self.professioanlDetailsAH.count {
let fullAddress = "\(self.professioanlDetailsAH[i]["searchAddress"]!)"
if !fullAddress.isEmpty {
var geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(fullAddress) { (placemarks, error) in
guard
let placemarks = placemarks,
let addressLocation = placemarks.first?.location
else {
// handle no location found
return
}
let latitude = addressLocation.coordinate.latitude
let longitude = addressLocation.coordinate.longitude
}
}
}
}
Edit:
func loadMarkers() {
for i in 0..<self.professioanlDetailsAH.count {
print(self.professioanlDetailsAH[i]["firstName"]!)
let fullAddress = "\(self.professioanlDetailsAH[i]["searchAddress"]!)"
print(fullAddress)
if !fullAddress.isEmpty {
geoCoder.geocodeAddressString(fullAddress) {(placemarks, error) in
if error != nil {
print(error!)
}
else{
guard
let placemarks = placemarks,
let addressLocation = placemarks.first?.location
else {return}
let latitude = addressLocation.coordinate.latitude
let longitude = addressLocation.coordinate.longitude
print("lat:\(latitude), long:\(longitude)")
}
}
}
}

Having trouble retrieving data from CloudKit

I am having trouble fetching the locations from cloudkit. The location gets uploaded, but when I try to have them printed out and loaded, they aren't downloaded. I don't get any errors.
This function uploads the location to CloudKit:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.015, longitudeDelta: 0.015))
self.mapView.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()//
let locationRecord = CKRecord(recordType: "location")
locationRecord.setObject(location, forKey: "location")
let publicData = CKContainer.defaultContainer().publicCloudDatabase
publicData.saveRecord(locationRecord) { record, error in
}
if error == nil
{
print("Location saved")
}
event1 = locations
}
This function fetches the locations from CloudKit:
func loadLocation()
{
let locations = [CKRecord]()
let publicData1 = CKContainer.defaultContainer().publicCloudDatabase
let query1 = CKQuery(recordType: "location", predicate: NSPredicate(format: "TRUEPREDICATE", argumentArray:nil))
publicData1.performQuery(query1, inZoneWithID: nil) { (results: [CKRecord]?, error: NSError?) -> Void in
if let locations = results
{
self.locations = locations
print(locations)
}
}
}
So to do this I made a unit test, that passes:
//
// CloudKitLocationsTests.swift
//
import XCTest
import UIKit
import CoreLocation
import CloudKit
class CloudKitLocationsTests: XCTestCase {
let locations = [ CLLocation(latitude: 34.4, longitude: -118.33), CLLocation(latitude: 32.2, longitude: -121.33) ]
func storeLocationToCloud(location:CLLocation) {
let locationRecord = CKRecord(recordType: "location")
locationRecord.setObject(location, forKey: "location")
let publicData = CKContainer.defaultContainer().publicCloudDatabase
publicData.saveRecord(locationRecord) { (records, error) in
if error != nil {
print("error saving locations: \(error)")
} else {
print("Locations saved: \(records)")
}
}
}
func fetchLocationsFromCloud(completion: (error:NSError?, records:[CKRecord]?) -> Void) {
let query = CKQuery(recordType: "Location", predicate: NSPredicate(value: true))
CKContainer.defaultContainer().publicCloudDatabase.performQuery(query, inZoneWithID: nil){
(records, error) in
if error != nil {
print("error fetching locations")
completion(error: error, records: nil)
} else {
print("found locations: \(records)")
completion(error: nil, records: records)
}
}
}
func testSavingLocations(){
let testExpectation = expectationWithDescription("saveLocations")
var n = 0
for location in self.locations {
let locationRecord = CKRecord(recordType: "Location")
locationRecord["location"] = location
let publicData = CKContainer.defaultContainer().publicCloudDatabase
publicData.saveRecord(locationRecord) { (records, error) in
if error != nil {
print("error saving locations: \(error)")
} else {
print("Locations saved: \(records)")
}
n += 1
if n >= self.locations.count {
testExpectation.fulfill()
}
}
}
// do something then call fulfill (in callback)
waitForExpectationsWithTimeout(10){ error in
if error != nil {
XCTFail("timed out waiting on expectation: \(testExpectation)")
}
}
}
func testFetchingLocations(){
let testExpectation = expectationWithDescription("FetchLocations")
fetchLocationsFromCloud(){ (error, records) in
if error != nil {
XCTFail("error fetching locations")
} else {
XCTAssertGreaterThan(records!.count, 0)
}
// do something then call fulfill (in callback)
testExpectation.fulfill()
}
waitForExpectationsWithTimeout(10){ error in
if error != nil {
XCTFail("timed out waiting on expectation: \(testExpectation)")
}
}
}
}
Note that you had case mismatch Location/location. Also, I am doing a subscript to set the field value.
Run this it works. Getting the location from the location manger callback has nothing to do with CloudKit so you should be able to plug this in as you require.
One other thing: I did turn on the option to allow you to query on ID field for the Location record type.
If your problem is to retrieve an array of CLLocation, try this:
publicData1.performQuery(query1, inZoneWithID: nil) { records, error in
var locations = [CLLocation]()
if let records = records {
for record in records {
if let location = record["location"] as? CLLocation {
locations.append(location)
}
}
}
}

CLGeocoder reverseGeocodeLocation Energy leak issues

I am using a CLGeocoder().reverseGeocodeLocation and when it is ran, I get "very high" energy consumption and a bit of Overhead. Here's my code:
if CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse {
var currentLatCoord = Double()
if manager.location?.coordinate.latitude != nil {
currentLatCoord = (manager.location?.coordinate.latitude)!
} else {
currentLatCoord = 0.0
print("oops!")
}
var currentLongCoord = Double()
if manager.location?.coordinate.longitude != nil {
currentLongCoord = (manager.location?.coordinate.longitude)!
} else {
currentLongCoord = 0.0
print("oops!")
}
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: currentLatCoord, longitude: currentLongCoord)) { (placemarks, error) -> Void in
if error != nil {
print("oops!")
print(error)
return
}
let placeArray = placemarks as [CLPlacemark]!
var placeMark: CLPlacemark
placeMark = placeArray![0]
if let thoroughfare = placeMark.addressDictionary?["Thoroughfare"] as? String {
self.locationLabel.text = thoroughfare
} else {
self.locationLabel.text = "Error!"
print("oops!")
}
}
}
Here's the debugger:
If anyone could find out why, and I searched all over for the reasoning behind this and couldn't find it, please let me know!

getting ETA ios - completion handler - swift

I am new to IOS coding and using swift.
I am trying to calculate an ETA between 2 different points. when i convert the address to coordinates, i am storing those in a global var. problem is, since the value is set in a completion handler, when i make the call to calculate the ETA, the vars are not yet set. what would be another way to obtain the same result.
sourceCoords: CLLocationCoordinate2D?
destCoords: CLLocationCoordinate2D?
func getETA()
{
var locationManager:CLLocationManager = CLLocationManager();
locationManager.requestAlwaysAuthorization();
var authorizationStatus:CLAuthorizationStatus = CLLocationManager.authorizationStatus();
if(authorizationStatus == CLAuthorizationStatus.Authorized ||
authorizationStatus == CLAuthorizationStatus.AuthorizedWhenInUse)
{
let geoCoder = CLGeocoder()
let sourceAddress =
[kABPersonAddressStreetKey as NSString: "1 Stockton St",
kABPersonAddressCityKey: "San Francisco",
kABPersonAddressStateKey: "California",
kABPersonAddressZIPKey: "94108"]
//get coordinates
geoCoder.geocodeAddressDictionary(sourceAddress, completionHandler:
{
(placemarks: [AnyObject]!, error: NSError!) in
if error != nil {
println("Geocode failed with error: \(error.localizedDescription)")
} else if placemarks.count > 0 {
let placemark = placemarks[0] as CLPlacemark
let location = placemark.location
self.sourceCoords = location.coordinate
}
});
//var requestSource = MKMapItem.mapItemForCurrentLocation();
let addressDict =
[kABPersonAddressStreetKey as NSString: "2125 Chestnut St",
kABPersonAddressCityKey: "San Francisco",
kABPersonAddressStateKey: "California",
kABPersonAddressZIPKey: "94123"]
//get coordinates
geoCoder.geocodeAddressDictionary(addressDict, completionHandler:
{
(placemarks: [AnyObject]!, error: NSError!) in
if error != nil {
println("Geocode failed with error: \(error.localizedDescription)")
} else if placemarks.count > 0 {
let placemark = placemarks[0] as CLPlacemark
let location = placemark.location
self.destCoords = location.coordinate
}
});
let placeSource = MKPlacemark(coordinate: sourceCoords!,
addressDictionary: sourceAddress)
var requestSource = MKMapItem(placemark: placeSource);
println(placeSource.location.coordinate.latitude)
let place = MKPlacemark(coordinate: destCoords!,
addressDictionary: addressDict)
var requestDestination = MKMapItem(placemark: place);
println(place.location.coordinate.latitude)
var request:MKDirectionsRequest = MKDirectionsRequest();
request.setSource(requestSource);
request.setDestination(requestDestination);
request.transportType = MKDirectionsTransportType.Automobile;
request.requestsAlternateRoutes = false;
var directions:MKDirections = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler({
(response: MKDirectionsResponse!, error: NSError?) in
if error != nil{
println("Error")
}
if response != nil{
var mkRoute:MKRoute = response.routes.last as MKRoute;
println(mkRoute.expectedTravelTime)
println(mkRoute.distance)
for step in mkRoute.steps
{
println(step.instructions);
}
}
else{
println("No response")
}
println(error?.description)
})
}

Resources