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
Hide whitespace changes
Inline
Side-by-side
Location Tutorial/LocationSearch.swift
View file @
fc0ee1ad
...
@@ -2,8 +2,6 @@
...
@@ -2,8 +2,6 @@
// LocationFinder.swift
// LocationFinder.swift
// MapKit Testing Search Functionality
// MapKit Testing Search Functionality
//
//
// Created by Brian Porumb on 25.11.21.
//
import
Foundation
import
Foundation
import
Combine
import
Combine
...
@@ -11,7 +9,7 @@ import MapKit
...
@@ -11,7 +9,7 @@ import MapKit
class
LocationService
:
NSObject
,
ObservableObject
{
class
LocationService
:
NSObject
,
ObservableObject
{
// Differnt search states
// Differ
e
nt search states
enum
LocationStatus
:
Equatable
{
enum
LocationStatus
:
Equatable
{
case
idle
case
idle
case
noResults
case
noResults
...
@@ -37,11 +35,11 @@ class LocationService: NSObject, ObservableObject {
...
@@ -37,11 +35,11 @@ class LocationService: NSObject, ObservableObject {
self
.
searchCompleter
.
delegate
=
self
self
.
searchCompleter
.
delegate
=
self
// receive a stream from the queryFragment in the view
// 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
// sink returns the updated string after waiting the specified amount of time
queryCancellable
=
$
queryFragment
queryCancellable
=
$
queryFragment
.
receive
(
on
:
DispatchQueue
.
main
)
.
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
.
sink
(
receiveValue
:
{
fragment
in
// if fragment isn't empty then set the queryFrament to the current updated string
// 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
// MapKit Testing Search Functionality
//
//
// Created by Brian Porumb on 25.11.21.
//
import
SwiftUI
import
SwiftUI
...
...
Location Tutorial/ViewController.swift
View file @
fc0ee1ad
//
//
// ViewController.swift
// ViewController.swift
// Location Tutorial
// MapKit Routing, Annotations and Location
//
// Created by Huang on 2021/11/25.
//
//
import
UIKit
import
UIKit
...
@@ -14,26 +12,31 @@ class ViewController: UIViewController {
...
@@ -14,26 +12,31 @@ class ViewController: UIViewController {
@IBOutlet
weak
var
mapView
:
MKMapView
!
@IBOutlet
weak
var
mapView
:
MKMapView
!
let
locationManager
=
CLLocationManager
()
let
locationManager
=
CLLocationManager
()
var
regionInMeters
:
Double
=
10000
//scale of the map
var
regionInMeters
:
Double
=
10000
//scale of the map
// ### code for directions start ###
var
directionsArray
:
[
MKDirections
]
=
[]
var
directionsArray
:
[
MKDirections
]
=
[]
// ### code for directions end ###
override
func
viewDidLoad
()
{
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
super
.
viewDidLoad
()
checkLocationServices
()
checkLocationServices
()
setupMapView
()
setupMapView
()
}
}
func
setupMapView
(){
mapView
.
delegate
=
self
}
func
setupLocationManager
()
{
func
setupLocationManager
()
{
locationManager
.
delegate
=
self
locationManager
.
delegate
=
self
locationManager
.
desiredAccuracy
=
kCLLocationAccuracyBest
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
()
{
func
centerViewOnUserLocation
()
{
if
let
location
=
locationManager
.
location
?
.
coordinate
{
if
let
location
=
locationManager
.
location
?
.
coordinate
{
let
region
=
MKCoordinateRegion
.
init
(
center
:
location
,
latitudinalMeters
:
regionInMeters
,
longitudinalMeters
:
regionInMeters
)
let
region
=
MKCoordinateRegion
.
init
(
center
:
location
,
latitudinalMeters
:
regionInMeters
,
longitudinalMeters
:
regionInMeters
)
...
@@ -41,18 +44,18 @@ class ViewController: UIViewController {
...
@@ -41,18 +44,18 @@ class ViewController: UIViewController {
}
}
}
}
// check if user's location services are enabled
func
checkLocationServices
()
{
func
checkLocationServices
()
{
if
CLLocationManager
.
locationServicesEnabled
()
{
if
CLLocationManager
.
locationServicesEnabled
()
{
setupLocationManager
()
setupLocationManager
()
checkLocationAuthorization
()
checkLocationAuthorization
()
}
else
{
}
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
()
{
func
checkLocationAuthorization
()
{
let
manager
=
CLLocationManager
()
let
manager
=
CLLocationManager
()
switch
manager
.
authorizationStatus
{
switch
manager
.
authorizationStatus
{
...
@@ -76,29 +79,24 @@ class ViewController: UIViewController {
...
@@ -76,29 +79,24 @@ class ViewController: UIViewController {
}
}
}
}
// ### code for directions start ###
// action triggered on the "GO" button tap
func
setupMapView
(){
mapView
.
delegate
=
self
}
@IBAction
func
goButtonTapped
(
_
sender
:
Any
)
{
@IBAction
func
goButtonTapped
(
_
sender
:
Any
)
{
print
(
"GO button tapped"
)
print
(
"GO button tapped"
)
getDirections
()
getDirections
()
}
}
func
getLocationCoordinates
()
->
CLLocationCoordinate2D
{
//to prevent throttling and multiple renders
let
cologne
=
MKPointAnnotation
()
func
resetMapView
(
withNew
directions
:
MKDirections
)
{
cologne
.
title
=
"Cologne"
mapView
.
removeOverlays
(
mapView
.
overlays
)
cologne
.
coordinate
=
CLLocationCoordinate2D
(
latitude
:
50.9375
,
longitude
:
6.9603
)
directionsArray
.
append
(
directions
)
mapView
.
addAnnotation
(
cologne
)
let
_
=
directionsArray
.
map
{
$0
.
cancel
()
}
return
cologne
.
coordinate
//hard coded coordinates for Cologne
}
}
// main function for routing
func
getDirections
()
{
func
getDirections
()
{
guard
let
location
=
locationManager
.
location
?
.
coordinate
else
{
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
return
}
}
...
@@ -107,12 +105,21 @@ class ViewController: UIViewController {
...
@@ -107,12 +105,21 @@ class ViewController: UIViewController {
resetMapView
(
withNew
:
directions
)
resetMapView
(
withNew
:
directions
)
directions
.
calculate
{
[
unowned
self
]
(
response
,
error
)
in
directions
.
calculate
{
[
unowned
self
]
(
response
,
error
)
in
//TODO: Handle error if needed
if
error
!=
nil
{
guard
let
response
=
response
else
{
return
}
//TODO: Show response not available in an alert
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
)
"
)
print
(
"total routes found:
\(
response
.
routes
.
count
)
"
)
for
route
in
response
.
routes
{
for
route
in
response
.
routes
{
self
.
mapView
.
addOverlay
(
route
.
polyline
,
level
:
.
aboveRoads
)
self
.
mapView
.
addOverlay
(
route
.
polyline
,
level
:
.
aboveRoads
)
//add an overlay for each route
var
directionsRegion
:
MKCoordinateRegion
=
MKCoordinateRegion
.
init
(
route
.
polyline
.
boundingMapRect
)
//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
//to increase the span of the region in order to add some margin
directionsRegion
.
span
.
latitudeDelta
*=
1.2
directionsRegion
.
span
.
latitudeDelta
*=
1.2
directionsRegion
.
span
.
longitudeDelta
*=
1.2
directionsRegion
.
span
.
longitudeDelta
*=
1.2
...
@@ -121,31 +128,30 @@ class ViewController: UIViewController {
...
@@ -121,31 +128,30 @@ class ViewController: UIViewController {
}
}
}
}
// creates a new request by configuring different properties
func
createDirectionsRequest
(
from
coordinate
:
CLLocationCoordinate2D
)
->
MKDirections
.
Request
{
func
createDirectionsRequest
(
from
coordinate
:
CLLocationCoordinate2D
)
->
MKDirections
.
Request
{
let
destinationCoordinate
=
getLocationCoordinates
()
let
destinationCoordinate
=
getLocationCoordinates
()
let
startingLocation
=
MKPlacemark
(
coordinate
:
coordinate
)
//user's location
let
startingLocation
=
MKPlacemark
(
coordinate
:
coordinate
)
//user's location
let
destination
=
MKPlacemark
(
coordinate
:
destinationCoordinate
)
let
destination
=
MKPlacemark
(
coordinate
:
destinationCoordinate
)
let
request
=
MKDirections
.
Request
()
let
request
=
MKDirections
.
Request
()
request
.
source
=
MKMapItem
(
placemark
:
startingLocation
)
request
.
source
=
MKMapItem
(
placemark
:
startingLocation
)
request
.
destination
=
MKMapItem
(
placemark
:
destination
)
request
.
destination
=
MKMapItem
(
placemark
:
destination
)
request
.
transportType
=
.
automobile
request
.
transportType
=
.
automobile
request
.
requestsAlternateRoutes
=
true
request
.
requestsAlternateRoutes
=
true
return
request
return
request
}
}
//to prevent throttling and multiple renders
// hard-coded to return coordinates of Southampton
func
resetMapView
(
withNew
directions
:
MKDirections
)
{
func
getLocationCoordinates
()
->
CLLocationCoordinate2D
{
mapView
.
removeOverlays
(
mapView
.
overlays
)
let
southampton
=
MKPointAnnotation
()
directionsArray
.
append
(
directions
)
southampton
.
title
=
"Southampton"
let
_
=
directionsArray
.
map
{
$0
.
cancel
()
}
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
{
extension
ViewController
:
CLLocationManagerDelegate
,
MKMapViewDelegate
{
func
locationManager
(
_
manager
:
CLLocationManager
,
didUpdateLocations
locations
:
[
CLLocation
])
{
func
locationManager
(
_
manager
:
CLLocationManager
,
didUpdateLocations
locations
:
[
CLLocation
])
{
...
@@ -158,7 +164,8 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
...
@@ -158,7 +164,8 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
checkLocationAuthorization
()
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
,
func
mapView
(
_
mapView
:
MKMapView
,
rendererFor
overlay
:
MKOverlay
)
->
MKOverlayRenderer
{
rendererFor
overlay
:
MKOverlay
)
->
MKOverlayRenderer
{
let
renderer
=
MKPolylineRenderer
(
overlay
:
overlay
)
let
renderer
=
MKPolylineRenderer
(
overlay
:
overlay
)
...
@@ -168,22 +175,22 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
...
@@ -168,22 +175,22 @@ extension ViewController: CLLocationManagerDelegate, MKMapViewDelegate {
return
renderer
return
renderer
}
}
// Delegate method for annotations
func
mapView
(
_
mapView
:
MKMapView
,
viewFor
annotation
:
MKAnnotation
)
->
MKAnnotationView
?
{
func
mapView
(
_
mapView
:
MKMapView
,
viewFor
annotation
:
MKAnnotation
)
->
MKAnnotationView
?
{
guard
annotation
is
MKPointAnnotation
else
{
return
nil
}
guard
annotation
is
MKPointAnnotation
else
{
return
nil
}
let
identifier
=
"Annotation"
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
)
var
annotationView
=
mapView
.
dequeueReusableAnnotationView
(
withIdentifier
:
identifier
)
if
annotationView
==
nil
{
if
annotationView
==
nil
{
annotationView
=
MKPinAnnotationView
(
annotation
:
annotation
,
reuseIdentifier
:
identifier
)
annotationView
=
MKPinAnnotationView
(
annotation
:
annotation
,
reuseIdentifier
:
identifier
)
annotationView
!.
canShowCallout
=
true
annotationView
!.
canShowCallout
=
true
}
else
{
}
else
{
annotationView
!.
annotation
=
annotation
annotationView
!.
annotation
=
annotation
}
}
return
annotationView
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