Refreshing location then running NSXMLParser - ios

My app (1) gets the user's location then (2) parses XML based on that location data. From load, the app works great. But I would like to get updated XML based on a change of location when the user taps the refresh button. I've tried several versions of this but can't get to work. I've included the portion of my code I think is relevant to this question (I think it's a timing issue). On tapping the refresh button, the location updates but the old XML is loaded:
class Myclass: UIPageViewController, UIPageViewControllerDataSource, CLLocationManagerDelegate, NSXMLParserDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.requestWhenInUseAuthorization()
//locationManager.requestLocation()
}
override func viewWillAppear(animated: Bool) {
switch CLLocationManager.authorizationStatus() {
case .AuthorizedWhenInUse, .AuthorizedAlways:
busyAlertController.display()
locationManager.requestLocation()
print("Authorized")
case .NotDetermined:
locationManager.requestWhenInUseAuthorization() // or request always if you need it
print("Not Determined")
case .Restricted, .Denied:
print("Restricted or Denied")
self.dismissViewControllerAnimated(true, completion: nil)
let alertController = UIAlertController(
title: "Background Location Access Disabled",
message: "We need to know your location to show you the correct forecast, please open this app's settings and set location access to 'When in Use' or 'Always'.",
preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Settings", style: .Default) { (action) in
if let url = NSURL(string:UIApplicationOpenSettingsURLString) {
UIApplication.sharedApplication().openURL(url)
}
}
alertController.addAction(openAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
// MARK: UIPageViewControllerDataSource & UIPageViewControllerDelegate
// MARK: - CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if (status == .AuthorizedAlways) || (status == .AuthorizedWhenInUse) {
locationManager.requestLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
let lat = "\(location.coordinate.latitude)"
let lon = "\(location.coordinate.longitude)"
let url = baseURL + lat + "&lon=" + lon + suffixURL
guard let urlAsNSURL = NSURL(string: url) else {return}
NWSURL = urlAsNSURL
runParser()
} else {
//TODO:
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error finding location: \(error.localizedDescription)")
showAlert("Location Problem", message: "We're having trouble finding your location, please try again.")
}
//XMLParser Methods
func parserDidEndDocument(parser: NSXMLParser){
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.showVC()
})
}
func runParser() {
guard let url = URL else {
return}
guard let parser = NSXMLParser(contentsOfURL: url) else {return}
parser.delegate = self
parser.parse()
}
#IBAction func refresh(sender: UIBarButtonItem) {
locationManager.requestLocation()
//runParser()
}
}

The locations array which was passed into locationManager:didUpdateLocations: may contain more than one location in case updates were deferred or multiple locations arrived before they could be delivered.
Since it is organized in the order in which the updates occurred, the most recent location update is at the end of the array.
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
...
}
}

The problem was that I wasn't clearing out a variable (array) after the NSXMLParser was done, and so I was appending over the stale data, yet since the stale data was first it was displaying in my UI and made it VERY hard to detect the problem until I printed to the console and saw the multiple arrays. I've done something similar before so note to anyone implementing NSXMLParser: make sure that you clear out the variable that you are using to store data in didEndElement.

Related

When using location manager, in xcode/swift, to get a user's current location, I get a value of nil. Any suggestions?

*UPDATE: Now getting location data, and the print statement print("\(currentLocation.coordinate.latitude)") works. If I try to assign what is on the right side of the = to a label.text value, I get an error: unexpectedly found nil while unwrapping an optional value. *
Still new to this whole Swift/Xcode thing. Any help would be greatly appreciated. I'm running the following code (only code relevant to the issue shown). When a user presses a button and selects get location, it is supposed to get their location. Instead, I'm getting nothing. The text in the locationManager never prints and I'm at a loss.
import UIKit
import MapKit
import CoreLocation
import MessageUI
import Photos
import AVFoundation
class ViewController: UIViewController, UITextViewDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, CLLocationManagerDelegate, MFMailComposeViewControllerDelegate {
var locationManager: CLLocationManager()
var currentLocation: CLLocation?
override func viewDidLoad() {
super.viewDidLoad()
locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let currentLocation = locations[0]
print("\(currentLocation.coordinate.latitude)")
issueLocation.text = "\(currentLocation.coordinate.latitude)" ***ERROR***
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error: \(error)")
}
Stuff that doesn't matter, I hope, and more code
// Attach a location
#IBAction func attachLocation(_ sender: UIButton) {
if issueLocation.text == nil {
issueImage.isHidden = true
}
let alertController = UIAlertController(title: "Location options", message: nil, preferredStyle: .actionSheet)
// Get location
let locationAction = UIAlertAction(title: "Get location", style: .default) { (action) in
self.displayLocation()
}
// Add get location action to alert controller
alertController.addAction(locationAction)
// Remove location
let eraseLocation = UIAlertAction(title: "Erase location", style: .default) { (action) in
self.issueLocation.text == nil
self.issueLocation.isHidden = true
}
// Add erase location to alert controller
alertController.addAction(eraseLocation)
// Cancel action
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
// Do nothing
}
// Add cancel action to alert controller
alertController.addAction(cancelAction)
// Display alert message on screen
self.present(alertController, animated: true) {
// Code to handle user selection
}
}
func displayLocation() {
let status = CLLocationManager.authorizationStatus()
let noPermissionMessage = "It appears that LoCAL Information does not have access to your location. Click Settings -> LoCAL Information -> Location to allow access to your location."
switch status {
case .notDetermined:
locationManager?.requestWhenInUseAuthorization()
case .authorized, .authorizedAlways, .authorizedWhenInUse:
print("JJJJJ")
print("KKKKK")
issueLocation.isHidden = false
case .denied, .restricted:
self.troubleAlert(message: noPermissionMessage)
#unknown default:
self.troubleAlert(message: noPermissionMessage)
}
}
locationManager is declared but not initialized
Replace
var locationManager: CLLocationManager?
with
let locationManager = CLLocationManager()
and remove the question mark after each occurrence of locationManager

CLLocation Manager check requestAlwaysAuthorization and if not accept exit app

I have requestAlwaysAuthorization and I need to track users every time if user doesn't accept to requestAlwaysAuthorization I want to do exit in app ?
How can I do it ?
My codes under below.
import CoreLocation
public var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let altitudeG = locations.last?.altitude
let longitudeG = locations.last?.coordinate.longitude
let latitudeG = locations.last?.coordinate.latitude
print("\(altitudeG) \(longitudeG) \(latitudeG)")
}
In error case this delegatemethod is called:
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error)
// handle not authorized error here. You might want to quit on specific errors (unauthorized) only. Check the error.
UIControl().sendAction(#selector(URLSessionTask.suspend), to: UIApplication.shared, for: nil)
}
You can also check the current permissions state before letting CLLocationManager fail:
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
print("No access")
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
}
} else {
print("Location services are not enabled")
}
taken from this answer.
Opinion based: I consider quitting the app instead of giving the user a understandable feedback very bad UX.
Above answer is also good, I just tried to make it bit easy way with methods. Also, if you are working with hardware devices like beacons then you must access the location AuthorizedAlways.
Check if location services are enabled
public func isLocationEnabled()-> Bool {
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .NotDetermined, .Restricted, .Denied , .AuthorizedWhenInUse :
showLocationServiceNotEnabledAlert()
return false
case .AuthorizedAlways: // As of now we check for only "Always", not for "When In Use" this should be fixed according to the requirements
return true
}
}
return false
}
Alert For User to on the service And redirect to Settings
func showLocationServiceNotEnabledAlert() {
let title = "Your Title"
let message = "Your Message"
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let settingsAction = UIAlertAction(title: "Settings".localized, style: .Default) { (alertAction) in
if let appSettings = NSURL(string: UIApplicationOpenSettingsURLString) {
UIApplication.sharedApplication().openURL(appSettings)
}
}
alertController.addAction(settingsAction)
let cancelAction = UIAlertAction(title: "Cancel".localized, style: .Cancel, handler: nil)
alertController.addAction(cancelAction)
UIApplication.sharedApplication().delegate?.window!?.currentViewController?.presentViewController(alertController, animated: true, completion: nil)
}

Repeating location data with CLLocation

This is a really basic outlay of what I am using...
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
// Call the locationManager class
let LocationManager = CLLocationManager()
// CoreData Delegate
let appDelegate = UIApplication.shared.delegate as! AppDelegate
override func viewDidLoad() {
super.viewDidLoad()
// Conform to Delegate Method
self.LocationManager.delegate = self
// Set required accuracy
self.LocationManager.desiredAccuracy = kCLLocationAccuracyBest
// Blue dot
self.mapView.showsUserLocation = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// check location services active
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// check location services
switch CLLocationManager.authorizationStatus() {
case .authorizedAlways:
self.LocationManager.startUpdatingLocation()
case .notDetermined:
self.LocationManager.requestAlwaysAuthorization()
case .authorizedWhenInUse, .restricted, .denied:
let alertController = UIAlertController(
title: "Background Location Access Disabled",
message: "In order to work your location settings need to be set to 'Always'.",
preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alertController.addAction(cancelAction)
let openAction = UIAlertAction(title: "Open Settings", style: .default) { (action) in
if let url = NSURL(string:UIApplicationOpenSettingsURLString) {
UIApplication.shared.open(url as URL)
}
}
alertController.addAction(openAction)
self.present(alertController, animated: true, completion: nil)
}
}
// Location delegate methods
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations)
// get last location
let location = locations.last
print(location!.coordinate.latitude)
// set region
let region = MKCoordinateRegion(center: location!.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
// deploy region to map
self.mapView.setRegion(region, animated: true)
// Map to follow the user
self.mapView.setUserTrackingMode(MKUserTrackingMode.follow, animated: true)
// Show compass on map
self.mapView.showsCompass = true
// save the location data to CoreData
//self.save(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
// end Location updating
self.LocationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Errors: " + error.localizedDescription)
}
}
My issue is that func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation] calls itself over and over again (around 3 times on initial load)...
I am using the .last which AFAIK is meant to pull out the last result in that object.. which it probably is, as with breakpoints inserted it after the first 2 prints it only returns 1 lot of results...
After searching high and low, I am hoping I can get a result by asking the question... Thanks!
Console output of my issue:
When you call startUpdatingLocation() the location manager immediately starts the delivering of location data. The first incoming locations may be way off your actual location, so check the horizontalAccuracy and verticalAccuracy attributes and dismiss locations which are too inaccurate.
It looks like you just want to get a one-shot location, if so try this code:
// Use:
// at class level:
// var manager: LocationOneShotManager?
// in viewDidLoad:
// manager = LocationOneShotManager()
// manager!.fetchWithCompletion {location, error in
// // fetch location or an error
// if let loc = location {
// println(location)
// } else if let err = error {
// println(err.localizedDescription)
// }
// self.manager = nil
// }
import UIKit
import CoreLocation
// possible errors
enum OneShotLocationManagerErrors: Int {
case AuthorizationDenied
case AuthorizationNotDetermined
case InvalidLocation
}
class LocationOneShotManager: NSObject, CLLocationManagerDelegate {
// location manager
private var locationManager: CLLocationManager?
// destroy the manager
deinit {
locationManager?.delegate = nil
locationManager = nil
}
typealias LocationClosure = ((location: CLLocation?, error: NSError?)->())
private var didComplete: LocationClosure?
// location manager returned, call didcomplete closure
private func _didComplete(location: CLLocation?, error: NSError?) {
locationManager?.stopUpdatingLocation()
didComplete?(location: location, error: error)
locationManager?.delegate = nil
locationManager = nil
}
// location authorization status changed
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .AuthorizedWhenInUse:
self.locationManager!.startUpdatingLocation()
case .Denied:
_didComplete(nil, error: NSError(domain: self.classForCoder.description(),
code: OneShotLocationManagerErrors.AuthorizationDenied.rawValue,
userInfo: nil))
default:
break
}
}
internal func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
_didComplete(nil, error: error)
}
internal func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
_didComplete(location, error: nil)
}
// ask for location permissions, fetch 1 location, and return
func fetchWithCompletion(completion: LocationClosure) {
// store the completion closure
didComplete = completion
// fire the location manager
locationManager = CLLocationManager()
locationManager!.delegate = self
// check for description key and ask permissions
if (NSBundle.mainBundle().objectForInfoDictionaryKey("NSLocationWhenInUseUsageDescription") != nil) {
locationManager!.requestWhenInUseAuthorization()
} else if (NSBundle.mainBundle().objectForInfoDictionaryKey("NSLocationAlwaysUsageDescription") != nil) {
locationManager!.requestAlwaysAuthorization()
} else {
fatalError("To use location in iOS8 you need to define either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription in the app bundle's Info.plist file")
}
}
}

CLLocationManager didUpdateLocations not being called

I am in the process of learning iOS 8 app development with Swift. I have followed a tutorial on Treehouse that walks you through building a weather app in Swift and iOS 8.
As an improvement to the app, the author/tutor suggests using CLLocationManager to get the location of the device to feed into the weather API instead of the hard coded latitude and longitude values.
So having read various tutorial online, I have gone ahead and attempted to implement this suggested improvement.
I have placed the code responsible for getting the location coordinates inside the AppDelegate.swift file.
AppDelegate.swift Code
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
var window: UIWindow?
var locationManager: CLLocationManager!
var errorOccured: Bool = false
var foundLocation: Bool = false
var locationStatus: NSString = "Not Started"
var location: CLLocationCoordinate2D?
var locationName: String?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
application.setStatusBarHidden(true, withAnimation: .None)
initializeLocationManager()
return true
}
func initializeLocationManager() {
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
println("didUpdateLocations running")
if (foundLocation == false) {
self.locationManager.stopUpdatingLocation()
foundLocation = true
var locationArray = locations as NSArray
var locationObj = locationArray.lastObject as CLLocation
var geoCoder = CLGeocoder()
geoCoder.reverseGeocodeLocation(locationObj, completionHandler: { (placemarks, error) -> Void in
var p = placemarks as NSArray
var placemark: CLPlacemark? = p.lastObject as? CLPlacemark
self.locationName = placemark?.name
})
self.location = locationObj.coordinate
}
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
locationManager.stopUpdatingLocation()
if ((error) != nil) {
if (errorOccured == false) {
errorOccured = true
print(error)
}
}
}
// authorization status
func locationManager(manager: CLLocationManager!,
didChangeAuthorizationStatus status: CLAuthorizationStatus) {
var shouldIAllow = false
switch status {
case CLAuthorizationStatus.Restricted:
locationStatus = "Restricted Access to location"
case CLAuthorizationStatus.Denied:
locationStatus = "User denied access to location"
case CLAuthorizationStatus.NotDetermined:
locationStatus = "Status not determined"
default:
locationStatus = "Allowed to location Access"
shouldIAllow = true
}
NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
if (shouldIAllow == true) {
NSLog("Location to Allowed")
// Start location services
locationManager.startUpdatingLocation()
} else {
NSLog("Denied access: \(locationStatus)")
}
}
}
And then in my ViewController.swift file I want to obtain the location coordinates. Here is the code:
ViewController.swift Code
func getCurrentWeatherData() -> Void {
let baseURL = NSURL(string: "https://api.forecast.io/forecast/\(apiKey)/")
var forecastURL: NSURL
var locName = "London"
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.foundLocation = false
if let loc = appDelegate.location {
println("Got Location!") // for debug purposes
var currentLat = loc.latitude
var currentLng = loc.longitude
forecastURL = NSURL(string: "\(currentLat),\(currentLng)", relativeToURL: baseURL)
locName = appDelegate.locationName!
} else {
println("No Location :(") // for debug purposes
var currentLat = "51.513445"
var currentLng = "-0.157828"
forecastURL = NSURL(string: "\(currentLat),\(currentLng)", relativeToURL: baseURL)
}
let sharedSession = NSURLSession.sharedSession()
let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in
var urlContents = NSString.stringWithContentsOfURL(location, encoding: NSUTF8StringEncoding, error: nil)
if (error == nil) {
let dataObject = NSData(contentsOfURL: location)
let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject, options: nil, error: nil) as NSDictionary
let currentWeather = Current(weatherDictionary: weatherDictionary)
dispatch_async(dispatch_get_main_queue(), {
() -> Void in
self.locationNameLabel.text = "\(locName)"
self.temperatureLabel.text = "\(currentWeather.temperature)"
self.iconView.image = currentWeather.icon!
self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is"
self.humidityLabel.text = "\(currentWeather.humidity)"
self.percipitationLabel.text = "\(currentWeather.percipProbability)"
self.summaryLabel.text = "\(currentWeather.summary)"
// Stop refresh animation
self.refreshActivityIndicator.stopAnimating()
self.refreshActivityIndicator.hidden = true
self.refreshButton.hidden = false
})
} else {
let networkIssueController = UIAlertController(title: "Error", message: "Unable to load data. Connectivity error!", preferredStyle: .Alert)
let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
networkIssueController.addAction(okButton)
let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
networkIssueController.addAction(cancelButton)
self.presentViewController(networkIssueController, animated: true, completion: nil)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.refreshActivityIndicator.stopAnimating()
self.refreshActivityIndicator.hidden = true
self.refreshButton.hidden = false
})
}
})
downloadTask.resume()
}
The above is not working. My didUpdateLocations delegate never gets called. And in the debug console/output I always get No Location :( printed out, suggesting a failure in getting the location, more specifically suggesting that the location property on my AppDelegate is nil.
Things I have done to remedy this:
In the info.plist I have added the two keys NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription
Ensured that I am connected via WiFi and not Ethernet
And countless other code tweaks, and still nothing.
A couple of observations:
As you point out, if you're going to call requestAlwaysAuthorization, then you must set NSLocationAlwaysUsageDescription. If you called requestWhenInUseAuthorization, you'd need NSLocationWhenInUseUsageDescription. (The fact that you see the confirmation dialog means that you've done this correctly. I assume you are seeing whatever description you supplied in the confirmation alert.)
On your simulator, you may not see location updates like on a device. Test this on an actual device.
When I used your code, I see didUpdateLocations when I called this from a device, but not from the simulator.
Once you solve the issue of not seeing didUpdateLocations being called, there is another issue:
You are posting a notification when the authorization status changes, but not when a location is received asynchronously (i.e. later). Frankly, the latter is the more critical event from the view controller's perspective, so I would have thought that (a) you should post a notification when the location is received; and (b) the view controller should observe this notification. Right now, even if you succeed in getting didUpdateLocations to be called, the view controller won't be notified of such.
Also, your didUpdateLocations is initiating yet another asynchronous process, the geocode of the coordinate. If your view controller needs that, too, you should post a notification inside the completion block of the geocoder.
Frankly, you haven't even shown us the view controller code that adds an observer for whatever notifications that this CLLocationManagerDelegate code will invoke, but I assume you have done that.
Just for the record: I first put the two keys (NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription) into the test-plist instead of the application-plist..Took me some time to realize.....

Getting Location in viewDidLoad

I am trying to get the user location but it doesn't work when the view loads. I have a refresh method that works just fine but that requires the user to tap a refresh button. The user location appears on the map when the view loads but in getLocation(), myLocation is nil. And again, tapping the refresh button that calls refreshLocation() works as expected.
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
mapView.userTrackingMode = .follow
getLocationAuthorizationStatus()
}
Request Authorization
func getLocationAuthorizationStatus() {
print("getLocationAuthorizationStatus()")
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManager.requestWhenInUseAuthorization()
} else if CLLocationManager.authorizationStatus() == .denied {
// Display UIAlertController
let locationDeniedAlert = BasicAlert(title: "", message: "Location services were denied. Please enable location services in Settings.", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default, handler: {
(action) -> Void in
let settingsURL = URL(string: UIApplicationOpenSettingsURLString)
if let url = settingsURL {
// UIApplication.shared.openURL(url)
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
locationDeniedAlert.dismiss(animated: true, completion: nil)
})
locationDeniedAlert.addAction(settingsAction)
self.present(locationDeniedAlert, animated: true, completion: nil)
} else if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
if fromSearch {
fromSearch = false
} else {
getLocation()
}
}
}
Get Location
func getLocation() {
print("getLocation()")
locationManager.startUpdatingLocation()
if locationManager.location != nil {
myLocation = locationManager.location!
if mapView.annotations.count == 1 && mapView.annotations[0] as! MKUserLocation == mapView.userLocation {
retrieveGymsWithLocation()
}
} else {
myLocation = nil
print("location = nil")
}
}
#objc func refreshLocation() {
print("refreshLocation()")
let annotationsToRemove = mapView.annotations
mapView.removeAnnotations(annotationsToRemove)
gyms.removeAll()
imageArrays.removeAll()
gymLocations.removeAll()
getLocationAuthorizationStatus()
}
Location Manager
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
myLocation = locations.last
}
It takes a while for CLLocationManager to determine the current location, depending on gps satellite availability and other kinds of influence. Therefore, you'll simply have to wait a while until the location property is set.
You typically would do this in the delegate method:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
manager.stopUpdatingLocation()
myLocation = locations.last
if mapView.annotations.count == 1 && mapView.annotations[0] as! MKUserLocation == mapView.userLocation {
retrieveGymsWithLocation()
}
}

Resources