Double Variable in Mkmapitem Array

Double variable in MKMapItem array

Updated so the sample deduplicates by name:

var seenNames = Set<String>()
for (index , name) in response.mapItems.enumerated() {
let item = response.mapItems[index]
if(checkIfDatabaseGotThis(key: String(name.name!)) != nil && !seenNames.contains(item.name)){
self.matchingItems.append(item)
seenNames.insert(item.name)
self.tableView.reloadData()
}
}

That should remove all duplicates from your list of items based on the name. It keeps track of all the existing names that you have seen. If the name hasn't been seen before, the item is added to the list. Otherwise it is ignored.

Swift Organize UITableView by Users Distance from MKMapItems

Sort them by distance:

func sortedMapItems() -> [MKMapItem] {
return self.mapItems.sorted(by: { (a, b) -> Bool in
return self.userLocation.location!.distance(from: a.placemark.location!) >
self.userLocation.location!.distance(from: b.placemark.location!)
})
}

EDIT: Create a function to sort your mapitems then call it in viewDidLoad:

override func viewDidLoad() {
super.viewDidLoad()
self.sortMapItems()

}
func sortMapItems() {
self.mapItems = self.mapItems.sorted(by: { (a, b) -> Bool in
return self.userLocation.location!.distance(from: a.placemark.location!) > self.userLocation.location!.distance(from: b.placemark.location!)
})
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return mapItems.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "resultCell", for: indexPath) as! ListedTableViewCell
// Configure the cell...
let row = indexPath.row
let item = mapItems[row]
cell.nameLabel.text = item.name
cell.detailLabel.text = item.phoneNumber
let distanceInMeters : Double = self.userLocation.location!.distance(from: mapItems[row].placemark.location!)
let distanceInMiles : Double = ((distanceInMeters.description as String).doubleValue * 0.00062137)
cell.distanceLabel.text = "\(distanceInMiles.string(2)) miles away"

return cell
}

Calling the original function (sortedMapItems) in this answer in cellForRowRowAtIndexPath will be too heavy and unnecessary because the function will be called repeatedly.

A better approach would be re-create your data structure and add the distance of each items from user's location so that you won't have to call distance function again in your cellForRow..

Using MKLocalSearch CompletionHandler correctly

The problem would be that search.start is ASYNCHRONOUS, it will start the request and return before results are done. Assume you need to work in completion handler.
Replace:

@IBAction func searchButtonPressed(_ sender: Any) {
search()
print(self.mapItems)
//chooseRandomSearchResult(results: self.mapItems!)

}

To: (Remove the usage of the results as they are not there yet, literally the search has been fired but has not returned)

 @IBAction func searchButtonPressed(_ sender: Any) {
search()
}

AND do the actual work in the callback:

//Still inside search()
search.start { (response, error) in
//Executed after search() has already returned
print(response?.mapItems)
self.mapItems = response?.mapItems
chooseRandomSearchResult(results: self.mapItems!)
}
//Still inside search()

As you can see the code marked:
//Executed after search() has already returned
ALWAYS executes after //Still inside search()
even if it is before it in the function

(As of iOS 11.x, the documentation guarantees the completion handler for MKLocalSearch.start will be on the main thread)

Accessing MKLocalSearchResponse item (swift)

The answer is:

var newRecordAddress = (localSearchResponse.mapItems[0] as! MKMapItem).placemark

This object contains all information you need. Checked it in demo project

Address only:

var newRecordAddress = (localSearchResponse.mapItems[0] as! MKMapItem).placemark
let addressOnly = newRecordAddress.name + ", " + newRecordAddress.title

newRecordAddress.name is place's name
newRecordAddress.title is place's address you required

Cannot wait for the result of MKDirections.calculate, getting nil instead of it

Using MapKit & Swift 5

Calculate distance between two location location, It will help anyone

Sample Function : I have tested in Google Map as well as Apple Map

        let startLocation : CLLocation = CLLocation.init(latitude: 23.0952779, longitude: 72.5274129)
let endLocation : CLLocation = CLLocation.init(latitude: 23.0981711, longitude: 72.5294229)
let distance = startLocation.distance(from: endLocation)
self.getDistance(departureDate: Date().adjust(hour: 8, minute: 0, second: 0, day: 0, month: 0), arrivalDate: Date().adjust(hour: 8, minute: 10, second: 0, day: 0, month: 0), startLocation: startLocation, endLocation: endLocation) { (distanceInMeters) in

print("fake distance: \(distance)")
let fakedistanceInMeter = Measurement(value: distance, unit: UnitLength.meters)
let fakedistanceInKM = fakedistanceInMeter.converted(to: UnitLength.kilometers).value
let fakedistanceInMiles = fakedistanceInMeter.converted(to: UnitLength.miles).value
print("fakedistanceInKM :\(fakedistanceInKM)")
print("fakedistanceInMiles :\(fakedistanceInMiles)")

print("actualDistance : \(distanceInMeters)")

let distanceInMeter = Measurement(value: distanceInMeters, unit: UnitLength.meters)
let distanceInKM = distanceInMeter.converted(to: UnitLength.kilometers).value
let distanceInMiles = distanceInMeter.converted(to: UnitLength.miles).value
print("distanceInKM :\(distanceInKM)")
print("distanceInMiles :\(distanceInMiles)")
}

Use of functions

                    self.getDistance(departureDate: trip.departure.dateTime, arrivalDate: trip.arrival.dateTime, startLocation: startLocation, endLocation: endLocation) { (actualDistance) in
print("actualDistance : \(actualDistance)")
}

I am improved above function and added code here, I hope it will help someone.

func calculateDistancefrom(departureDate: Date, arrivalDate: Date, sourceLocation: MKMapItem, destinationLocation: MKMapItem, doneSearching: @escaping (_ distance: CLLocationDistance) -> Void) {

let request: MKDirections.Request = MKDirections.Request()

request.departureDate = departureDate
request.arrivalDate = arrivalDate

request.source = sourceLocation
request.destination = destinationLocation

request.requestsAlternateRoutes = true
request.transportType = .automobile

let directions = MKDirections(request: request)
directions.calculate { (directions, error) in
if var routeResponse = directions?.routes {
routeResponse.sort(by: {$0.expectedTravelTime <
$1.expectedTravelTime})
let quickestRouteForSegment: MKRoute = routeResponse[0]

doneSearching(quickestRouteForSegment.distance)
}
}
}

func getDistance(departureDate: Date, arrivalDate: Date, startLocation : CLLocation, endLocation : CLLocation, completionHandler: @escaping (_ distance: CLLocationDistance) -> Void) {

let destinationItem = MKMapItem(placemark: MKPlacemark(coordinate: startLocation.coordinate))
let sourceItem = MKMapItem(placemark: MKPlacemark(coordinate: endLocation.coordinate))
self.calculateDistancefrom(departureDate: departureDate, arrivalDate: arrivalDate, sourceLocation: sourceItem, destinationLocation: destinationItem, doneSearching: { distance in
completionHandler(distance)
})
}

Route not showing in MKMapView?

Actually both source and destination variables were nil.. So i got bad response from the server.If you need just try the below code

func addRoutesOverLayForMapView(){

var source:MKMapItem?
var destination:MKMapItem?
var sourcePlacemark = MKPlacemark(coordinate: pickUpDistanceLocation!.coordinate, addressDictionary: nil)
source = MKMapItem(placemark: sourcePlacemark)

var desitnationPlacemark = MKPlacemark(coordinate: dropOffDistanceLocation!.coordinate, addressDictionary: nil)
destination = MKMapItem(placemark: desitnationPlacemark)
let request:MKDirectionsRequest = MKDirectionsRequest()
request.setSource(source)
request.setDestination(destination)
request.transportType = MKDirectionsTransportType.Walking

let directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler ({
(response: MKDirectionsResponse?, error: NSError?) in

if error == nil {

self.showRoute(response!)
}
else{

println("trace the error \(error?.localizedDescription)")

}
})
}

func showRoute(response:MKDirectionsResponse){
for route in response.routes as! [MKRoute]{
mapView.addOverlay(route.polyline, level: MKOverlayLevel.AboveRoads)
var routeSeconds = route.expectedTravelTime
let routeDistance = route.distance
println("distance between two points is \(routeSeconds) and \(routeDistance)")

}

}

And you should implement this delegate method,dont forget to set the mapview delegate

  func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {

if overlay is MKPolyline {
var polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.lineDashPattern = [14,10,6,10,4,10]
polylineRenderer.strokeColor = UIColor(red: 0.012, green: 0.012, blue: 0.012, alpha: 1.00)
polylineRenderer.lineWidth = 2.5
return polylineRenderer
}
return nil

}

Swift How to build a route FROM map Item, which I define in Search Bar

So I created an Array of mapItems, stored mapItems in it when table row is selected. Then when calling my buttons, using that array, I've assigned values to my source and destination points.



Related Topics



Leave a reply



Submit