Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Ariba Siddiqui
MapKit Directions
Commits
fc0ee1ad
Commit
fc0ee1ad
authored
Nov 29, 2021
by
Ariba Siddiqui
Browse files
Comments and otehr restrucuring
parent
1377bbc9
Changes
3
Show whitespace changes
Inline
Side-by-side
Location Tutorial/LocationSearch.swift
View file @
fc0ee1ad
...
...
@@ -2,8 +2,6 @@
// LocationFinder.swift
// MapKit Testing Search Functionality
//
// Created by Brian Porumb on 25.11.21.
//
import
Foundation
import
Combine
...
...
@@ -11,7 +9,7 @@ import MapKit
class
LocationService
:
NSObject
,
ObservableObject
{
// Differnt search states
// Differ
e
nt search states
enum
LocationStatus
:
Equatable
{
case
idle
case
noResults
...
...
@@ -37,11 +35,11 @@ class LocationService: NSObject, ObservableObject {
self
.
searchCompleter
.
delegate
=
self
// receive a stream from the queryFragment in the view
// debounce (wait) for
2
50miliseconds before pushing the event further
// debounce (wait) for 50
0
mil
l
iseconds before pushing the event further
// sink returns the updated string after waiting the specified amount of time
queryCancellable
=
$
queryFragment
.
receive
(
on
:
DispatchQueue
.
main
)
.
debounce
(
for
:
.
milliseconds
(
2
50
),
scheduler
:
RunLoop
.
main
,
options
:
nil
)
.
debounce
(
for
:
.
milliseconds
(
5
0
0
),
scheduler
:
RunLoop
.
main
,
options
:
nil
)
.
sink
(
receiveValue
:
{
fragment
in
// if fragment isn't empty then set the queryFrament to the current updated string
...
...
Location Tutorial/MapSerachView.swift
View file @
fc0ee1ad
//
//
Content
View.swift
//
MapSearch
View.swift
// MapKit Testing Search Functionality
//
// Created by Brian Porumb on 25.11.21.
//
import
SwiftUI
...
...
Location Tutorial/ViewController.swift
View file @
fc0ee1ad
//
// ViewController.swift
// Location Tutorial
//
// Created by Huang on 2021/11/25.
// MapKit Routing, Annotations and Location
//
import
UIKit
...
...
@@ -14,25 +12,30 @@ class ViewController: UIViewController {
@IBOutlet
weak
var
mapView
:
MKMapView
!
let
locationManager
=
CLLocationManager
()
var
regionInMeters
:
Double
=
10000
//scale of the map
// ### code for directions start ###
var
directionsArray
:
[
MKDirections
]
=
[]
// ### code for directions end ###
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
checkLocationServices
()
setupMapView
()
}
func
setupMapView
(){
mapView
.
delegate
=
self
}
func
setupLocationManager
()
{
locationManager
.
delegate
=
self
locationManager
.
desiredAccuracy
=
kCLLocationAccuracyBest
}
// helper function to display alerts to user
func
displayAlert
(
alertTitle
:
String
,
alertMessage
:
String
)
{
let
alert
=
UIAlertController
(
title
:
alertTitle
,
message
:
alertMessage
,
preferredStyle
:
.
alert
)
alert
.
addAction
(
UIAlertAction
(
title
:
"OK"
,
style
:
.
default
,
handler
:
nil
))
alert
.
addAction
(
UIAlertAction
(
title
:
"Cancel"
,
style
:
.
cancel
,
handler
:
nil
))
self
.
present
(
alert
,
animated
:
true
)
}
func
centerViewOnUserLocation
()
{
if
let
location
=
locationManager
.
location
?
.
coordinate
{
...
...
@@ -41,18 +44,18 @@ class ViewController: UIViewController {
}
}
// check if user's location services are enabled
func
checkLocationServices
()
{
if
CLLocationManager
.
locationServicesEnabled
()
{
setupLocationManager
()
checkLocationAuthorization
()
}
else
{
// Show alert letting the user know they have to turn this on.
print
(
"Location Services are not enabled"
)
displayAlert
(
alertTitle
:
"Location Services are not turned on"
,
alertMessage
:
"You must enable your Location Services to perform this action"
)
}
}
// checking authorization status
func
checkLocationAuthorization
()
{
let
manager
=
CLLocationManager
()
switch
manager
.
authorizationStatus
{
...
...
@@ -76,29 +79,24 @@ class ViewController: UIViewController {
}
}
// ### code for directions start ###
func
setupMapView
(){
mapView
.
delegate
=
self
}
// action triggered on the "GO" button tap
@IBAction
func
goButtonTapped
(
_
sender
:
Any
)
{
print
(
"GO button tapped"
)
getDirections
()
}
func
getLocationCoordinates
()
->
CLLocationCoordinate2D
{
let
cologne
=
MKPointAnnotation
()
cologne
.
title
=
"Cologne"
cologne
.
coordinate
=
CLLocationCoordinate2D
(
latitude
:
50.9375
,
longitude
:
6.9603
)
mapView
.
addAnnotation
(
cologne
)
return
cologne
.
coordinate
//hard coded coordinates for Cologne
//to prevent throttling and multiple renders
func
resetMapView
(
withNew
directions
:
MKDirections
)
{
mapView
.
removeOverlays
(
mapView
.
overlays
)
directionsArray
.
append
(
directions
)
let
_
=
directionsArray
.
map
{
$0
.
cancel
()
}
}
// main function for routing
func
getDirections
()
{
guard
let
location
=
locationManager
.
location
?
.
coordinate
else
{
//TODO: Inform user we don't have their current location
print
(
"Location not found"
)
displayAlert
(
alertTitle
:
"Location not found"
,
alertMessage
:
"App cannot access your location"
)
return
}
...
...
@@ -107,12 +105,21 @@ class ViewController: UIViewController {
resetMapView
(
withNew
:
directions
)
directions
.
calculate
{
[
unowned
self
]
(
response
,
error
)
in
//TODO: Handle error if needed
guard
let
response
=
response
else
{
return
}
//TODO: Show response not available in an alert
if
error
!=
nil
{
print
(
"Directions couldn't be computed"
)
displayAlert
(
alertTitle
:
"Directions couldn't be computed"
,
alertMessage
:
"App cannot find directions to the destination"
)
return
}
guard
let
response
=
response
else
{
print
(
"Response not found"
)
displayAlert
(
alertTitle
:
"Directions couldn't be computed"
,
alertMessage
:
"App cannot find directions to the destination"
)
return
}
print
(
"total routes found:
\(
response
.
routes
.
count
)
"
)
for
route
in
response
.
routes
{
self
.
mapView
.
addOverlay
(
route
.
polyline
,
level
:
.
aboveRoads
)
var
directionsRegion
:
MKCoordinateRegion
=
MKCoordinateRegion
.
init
(
route
.
polyline
.
boundingMapRect
)
self
.
mapView
.
addOverlay
(
route
.
polyline
,
level
:
.
aboveRoads
)
//add an overlay for each route
//polyline: connected line segments that don't form a loop
var
directionsRegion
:
MKCoordinateRegion
=
MKCoordinateRegion
.
init
(
route
.
polyline
.
boundingMapRect
)
// recenter
//to increase the span of the region in order to add some margin
directionsRegion
.
span
.
latitudeDelta
*=
1.2
directionsRegion
.
span
.
longitudeDelta
*=
1.2
...
...
@@ -121,31 +128,30 @@ class ViewController: UIViewController {
}
}
// creates a new request by configuring different properties
func
createDirectionsRequest
(
from
coordinate
:
CLLocationCoordinate2D
)
->
MKDirections
.
Request
{
let
destinationCoordinate
=
getLocationCoordinates
()
let
startingLocation
=
MKPlacemark
(
coordinate
:
coordinate
)
//user's location
let
destination
=
MKPlacemark
(
coordinate
:
destinationCoordinate
)
let
request
=
MKDirections
.
Request
()
request
.
source
=
MKMapItem
(
placemark
:
startingLocation
)
request
.
destination
=
MKMapItem
(
placemark
:
destination
)
request
.
transportType
=
.
automobile
request
.
requestsAlternateRoutes
=
true
return
request
}
//to prevent throttling and multiple renders
func
resetMapView
(
withNew
directions
:
MKDirections
)
{
mapView
.
removeOverlays
(
mapView
.
overlays
)
directionsArray
.
append
(
directions
)
let
_
=
directionsArray
.
map
{
$0
.
cancel
()
}
// hard-coded to return coordinates of Southampton
func
getLocationCoordinates
()
->
CLLocationCoordinate2D
{
let
southampton
=
MKPointAnnotation
()
southampton
.
title
=
"Southampton"
southampton
.
coordinate
=
CLLocationCoordinate2D
(
latitude
:
50.9097
,
longitude
:
-
1.4044
)
mapView
.
addAnnotation
(
southampton
)
// add annotation(a pin) for Southampton
return
southampton
.
coordinate
}
// ### code for directions end ###
}
extension
ViewController
:
CLLocationManagerDelegate
,
MKMapViewDelegate
{
func
locationManager
(
_
manager
:
CLLocationManager
,
didUpdateLocations
locations
:
[
CLLocation
])
{
...
...
@@ -158,7 +164,8 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
checkLocationAuthorization
()
}
// ### code for directions start ###
// called each time the bounding map rectangle of an overlay intersects the visible region of a map
// defines 'how' the overlay should look like -> renderer properties are specified here
func
mapView
(
_
mapView
:
MKMapView
,
rendererFor
overlay
:
MKOverlay
)
->
MKOverlayRenderer
{
let
renderer
=
MKPolylineRenderer
(
overlay
:
overlay
)
...
...
@@ -168,22 +175,22 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
return
renderer
}
// Delegate method for annotations
func
mapView
(
_
mapView
:
MKMapView
,
viewFor
annotation
:
MKAnnotation
)
->
MKAnnotationView
?
{
guard
annotation
is
MKPointAnnotation
else
{
return
nil
}
let
identifier
=
"Annotation"
// dequeue an existing annotation view before creating a new one as new annotations move on-screen
// (performance enhancement)
var
annotationView
=
mapView
.
dequeueReusableAnnotationView
(
withIdentifier
:
identifier
)
if
annotationView
==
nil
{
annotationView
=
MKPinAnnotationView
(
annotation
:
annotation
,
reuseIdentifier
:
identifier
)
annotationView
!.
canShowCallout
=
true
}
else
{
annotationView
!.
annotation
=
annotation
}
return
annotationView
}
// ### code for directions end ###
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment