How to request a start for startUpdatingLocation? - swift

I'm starting a location manager as i open the view with this code:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var userLocation: CLLocation = locations[0] as! CLLocation
userLatitude = userLocation.coordinate.latitude
userLongitude = userLocation.coordinate.longitude
if (userLocation.horizontalAccuracy < 80) {
manager.stopUpdatingLocation()
} else {
addMapRegionAndAnnotation()
}
}
So this means the locationManager does Stop if the location is detected in a 80m radius.
Now i want to start this locationManager again if i press my updateLocation button:
#IBAction func updatePostMapView(sender: AnyObject) {
manager.startUpdatingLocation()
}
Then the app shuold update the user location till the radius is smaller then 80m again...
But as you may expect, this isn't working because i can't call the manager.startUpdatingLocation() from outside of the locationManager.
Has anyone a solution?

You can call startUpdatingLocation() or stopUpdatingLocation() from inside of any method. First You must create location manager within your class,
class
let locationManager = CLLocationManager()
func initializeLocationManager()
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.distanceFilter=kCLLocationAccuracyNearestTenMeters
}
func anyMethod()
{
locationManager.stopUpdatingLocation()
locationManager.startUpdatingLocation()
}

Related

macos CLLocationManager Promt

I want to send location details when a push notification receives from server. But macos application doesn't ask location permission in launching. Added all privacy items in info.plist. It ask for permission when it calls locationmanager.startUpdatingLocation().And didn't ask again if i cancel it.The code is given below.
class AppDelegate: NSObject, NSApplicationDelegate, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
func applicationDidFinishLaunching(_ aNotification: Notification) {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func scanLocationRequest{
locationManager.startUpdatingLocation()
// Call this when a notification receives.
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let currentLocation = locations.last
locationManager.stopUpdatingLocation()
sendLocationReport(currentLocation: currentLocation!)
}
}
To check if user have location access or not use following code:
var isPermissionAvailable: Bool {
let status = CLLocationManager.authorizationStatus()
switch status {
case .authorizedAlways, .authorizedWhenInUse:
return true
case .denied, .restricted, .notDetermined:
requestForLocation()
return false
}
}
func requestForLocation() {
// Edit
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
To show pop-up at App launch, you can use following code in applicationDidFinishLaunching(_ aNotification:) in AppDelegate class:
if isPermissionAvailable {
// Do your work on permission available
}

I am having difficulty receiving a user's current location with Swift 2.0

I have been surfing the web for methods to get a user's current location in Swift 2.0, Unfortunately none have work. Here is the code I have been working on, but it cannot work. I have been playing with the info.plist file but don't know what to add? Can anyone tell me what I am doing wrong?
import CoreLocation
class ViewController: UIViewController {
let locationManager = CLLocationManager()
override func viewDidLoad(){
super.viewDidLoad()
findMyLocation()
}
func findMyLocation() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for location in locations {
print("THIS IS THE LATTITUDE \(location.coordinate.latitude)")
}
locationManager.stopUpdatingLocation()
}
}
EDIT: in your didUpdateLocations function don't force stopUpdatingLocation. This function is called multiple times before your location is finalized to be shown on the map. Remove that line and you'll see that your console will print 3-5 times with your lat and long.
The recommended way to get the user location is to always check to make sure you have the permission so that if you don't you can alert the user and ask for said permission.
In your viewDidLoad()
locationManager?.requestAlwaysAuthorization()
// .AuthorizedInUse or .AuthorizedAlways depending on your app
if CLLocationManager.authorizationStatus() == .AuthorizedInUse {
locationManager?.distanceFilter = 5.0
locationManager?.requestLocation()
}
This ensures that you're requesting authorization if there is none and checking if they declined. In addition utilize this function in your CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus)
{
//Again this can be .AuthorizedAlways or .AuthorizedInUse depending
if status == .AuthorizedAlways {
locationManager?.startUpdatingLocation()
// ...
}
}
This allows the app to respond properly if they change the location permissions in the middle of using your location services after the viewDidLoad().
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
centerLocation = location
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02))
userLocationRegion = region
mainMapView.showAnnotations(mainMapView.annotations, animated: true)
self.mainMapView.setRegion(region, animated: true)
}
you need to add NSLocationWhenInUseUsageDescription or/and NSLocationAlwaysUsageDescription depends on your use case

Core Location returns nil when asked for location

My private constant in my Custom class:
private let locationManager = CLLocationManager()
in viewDidLoad() I call the method:
private func setupLocationManager() {
locationManager.delegate = self
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
But when I ask about location at some time later:
println("-----\(locationManager.location)")
I get:
-----nil
Where is the problem? I run this on device. My app is allowed to use location...
You should not try to get location that way because getting location can take some time (for more information see GPS TTFF). Since your location manager already has a delegate you must get location in didUpdateLocations delegate method. Also always make sure you have the permission to use location before calling startUpdatingLocation
private func setupLocationManager() {
locationManager.delegate = self
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse || CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedAlways{
locationManager.startUpdatingLocation()
}else{
locationManager.requestWhenInUseAuthorization()
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!){
println(manager.location)
}
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.AuthorizedWhenInUse || status == CLAuthorizationStatus.AuthorizedAlways {
locationManager.startUpdatingLocation()
}
}

Swift: nil while unwrapping an Optional value. When trying to get user location

So I'm new to app development and I'm attempting to learn how user LocationManager works. My goal at this moment is to "ask for authorization" > check to see if it's authorized" > if true { get location and store coordinates in a variable }
here's my code:
let locationManager = CLLocationManager()
var coordinates: String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
aivRefresh.hidden = true
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!){
if locations != nil {
var location:CLLocationCoordinate2D = manager.location.coordinate
coordinates = "\(location.longitude),\(location.latitude)"
}

locationManager:didUpdateLocations: always be called several times

I start updating current location when the view did appear, and stop updating location whenever locationManager:didUpdateLocations: is called. But why the locationManager:didUpdateLocations: always be called several times? What have I missed?
#import "ViewController.h"
#interface ViewController (){
CLLocationManager *locationManager; // location manager for current location
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self startUpdatingCurrentLocation];
}
- (void)startUpdatingCurrentLocation
{
if (!locationManager)
{
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
locationManager.distanceFilter = 10.0f; // we don't need to be any more accurate than 10m
}
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[locationManager stopUpdatingLocation];
}
#end
Probably it depends about the accuracy you set to the locationManager. You have 3 kinds o localization Cell Radio, WiFi Map, GPS. If you set best as accuracy the location manager will continue to check you position, if the location with better accuracy is out of the range of the distance filter the delegate method will be called again.
SWIFT version
i made a helper class as HelperLocationManager and added a notification- observer pattern
import UIKit
import CoreLocation
class HelperLocationManager: NSObject {
var locationManager = CLLocationManager()
static let sharedInstance = HelperLocationManager()
var currentLocation :CLLocation?
var notGotUserLocation = true
override init() {
super.init()
var code = CLLocationManager.authorizationStatus()
if code == CLAuthorizationStatus.NotDetermined {
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
}
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
locationManager.delegate = self
locationManager.distanceFilter = 100;
}
}
extension HelperLocationManager: CLLocationManagerDelegate{
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue = locations.last as! CLLocation
println(locValue)
self.currentLocation = locValue
NSNotificationCenter.defaultCenter().postNotificationName("sendCurrentAddressToViewController", object:self.currentLocation)
notGotUserLocation = false
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("Your error is ", error.localizedDescription)
}
}
Now if your Viewcontroller class needs the location then put an observer there
var helperLocation:HelperLocationManager?
in viewDidLoad as
override func viewDidLoad() {
helperLocation = HelperLocationManager()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "getCurrentAddressToViewController:", name: "sendCurrentAddressToViewController", object: nil)
}
//and observer as
func getCurrentAddressToViewController(notification: NSNotification) {
currentLocation = notification.object as? CLLocation
NSNotificationCenter.defaultCenter().removeObserver(self, name: "sendCurrentAddressToViewController", object: nil)
}
//although didUpdateLocation is called multiple times you only get one time location because of removing observer after you get the location.
EDIT: I refractored this helper class so that you dont need to add notificationobserver pattern
class HelperLocationManager: NSObject {
private lazy var locationManager = CLLocationManager()
static let sharedInstance = HelperLocationManager()
var currentLocation :CLLocation?
override init() {
super.init()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
}
}
extension HelperLocationManager: CLLocationManagerDelegate{
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case CLAuthorizationStatus.NotDetermined:
locationManager.requestWhenInUseAuthorization()
case CLAuthorizationStatus.Restricted:
PrinterHelper.messagePrinter("Restricted Access to location")
case CLAuthorizationStatus.Denied:
PrinterHelper.messagePrinter("User denied access to location")
case CLAuthorizationStatus.AuthorizedWhenInUse:
if #available(iOS 9.0, *) {
locationManager.requestLocation()
} else {
locationManager.startUpdatingLocation()
}
default:
PrinterHelper.messagePrinter("default authorization")
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue = locations.last
HelperLocationManager.sharedInstance.currentLocation = locValue
locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
PrinterHelper.errorPrinter(error.localizedDescription)
}
}
View Controller where you need to get user Permission
var helperLocationManager:HelperLocationManager?
in viewDidLoad as
override func viewDidLoad() {
helperLocationManager = HelperLocationManager.sharedInstance
}
And to get the location you need to call the singleton property currentLocation as
if let userCurentLoc = HelperLocationManager.sharedInstance.currentLocation{
//userCurrentLoc is the user Location
}
To complement on Anish's answer, if you wanna know when your helper class didn't call the location update (i.e when you have turned off your location services), you can manage this using the locationManager:didChangeAuthorizationStatus: method, and if your location is not allowed, you can call another notification- observer
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
}
if (shouldIAllow == true) {
print("Location to Allowed")
// Start location services
locationManager!.startUpdatingLocation()
} else {
print("Denied access: \(locationStatus)")
NSNotificationCenter.defaultCenter().postNotificationName("deniedLocation", object:locationStatus)
}
}