CLLocationManager works only once - swift

I'm new to swift - currently, my current location is only output once in the console when I first call setupLocationManager() on init through override func awakeFromNib(). When I want it to output my new location by calling locationManager.startUpdatingLocation() when I click a button with the method updateLocation(), it prints an error. Any way to fix this? All help is appreciated.
import Cocoa
import CoreLocation
class StatusMenuController: NSObject, CLLocationManagerDelegate {
#IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
var locationManager:CLLocationManager!
var currentLocation:CLLocation?
#IBAction func quitClicked(_ sender: NSMenuItem) {
NSApplication.shared().terminate(self)
}
#IBAction func updateClicked(_ sender: NSMenuItem) {
updateLocation()
}
func updateLocation() {
locationManager.startUpdatingLocation()
}
override func awakeFromNib() {
statusItem.menu = statusMenu
let icon = NSImage(named: "statusIcon")
icon?.isTemplate = true
statusItem.image = icon
statusItem.menu = statusMenu
setupLocationManager()
}
func setupLocationManager(){
locationManager = CLLocationManager()
locationManager?.delegate = self
//self.locationManager?.requestAlwaysAuthorization()
locationManager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager?.startUpdatingLocation()
}
// Below method will provide you current location.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if currentLocation == nil {
currentLocation = locations.last
locationManager?.stopMonitoringSignificantLocationChanges()
let locationValue:CLLocationCoordinate2D = manager.location!.coordinate
print(locationValue)
locationManager?.stopUpdatingLocation()
}
}
// Below Method will print error if not able to update location.
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error")
}
}

There is an if condition in the code which suspends updating the location after the location is set once (if currentLocation == nil). You have to reset currentLocation to nil before restarting the manager.
#IBAction func updateClicked(_ sender: NSMenuItem) {
currentLocation = nil
updateLocation()
}

Related

How do I pass my longitude and latitude variables to another function?

I have the function "locationManager" where I create and set longitude and latitude. What I want to do is be able to get that location when the button is pushed. How can I get longitude and latitude into the #IBAction for when I press that button? Than you so much for your help!
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
setupLocationManager()
}
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
if location.horizontalAccuracy > 0 {
locationManager.stopUpdatingLocation()
let longitude = location.coordinate.longitude
let latitude = location.coordinate.latitude
print("longitude = \(longitude)")
print("latitude = \(latitude)")
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Location update failed, \(error)")
}
#IBAction func buttonPressed(_ sender: UIButton) {
// print(longitude)
}
}
Define your location variable if class scope
fileprivate var mylocation:CLLocation?
set mylocation in
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
if location.horizontalAccuracy > 0 {
locationManager.stopUpdatingLocation()
myLocation = location
}
}
}
now you can access location when button tap
#IBAction func buttonPressed(_ sender: UIButton) {
let longitude = myLocation.coordinate.longitude
let latitude = myLocation.coordinate.latitude
print("longitude = \(longitude)")
print("latitude = \(latitude)")
}

How to write the Swift code for checking the users location and only carrying out the function if they are in the geofence radius?

The goal is to only allow the data to be posted from tapping the "I'm Here" if the current users location is within the pre-defined geofence. If they are outside the bounds they will receive an alert error and the data will not be posted to the Firestore.
I've read about the didDetermineState but am having trouble understanding.
import UIKit
import Firebase
import FirebaseFirestore
import MapKit
import CoreLocation
class checkInViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var imHereButton: UIButton!
#IBOutlet weak var callUsButton: UIButton!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setUpElements()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
let geoFenceRegion:CLCircularRegion = CLCircularRegion(center: CLLocationCoordinate2DMake(xxxx, xxxx), radius: 5, identifier: "xxxx")
locationManager.startMonitoring(for: geoFenceRegion)
}
func setUpElements (){
Utilities.styleFilledButton(imHereButton)
Utilities.styleFilledButton(callUsButton)
}
#IBAction func backTapped(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Check-In Enabled")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("Check-In Disabled")
}
#IBAction func imHereTapped(_ sender: Any) {
guard let uid = Auth.auth().currentUser?.uid else { return }
guard let memberNumber = UserDefaults.standard.string(forKey: "memberNumber"), !memberNumber.isEmpty else
{ return }
guard let firstName = UserDefaults.standard.string(forKey: "firstName"), !firstName.isEmpty else
{ return }
guard let lastName = UserDefaults.standard.string(forKey: "lastName"), !lastName.isEmpty else
{ return }
let checkInData = ["name":"\(firstName) \(lastName)", "memberNumber":memberNumber, "userId": uid]
FirestoreReferenceManager.myReferenceForCheckIn().addDocument(data: checkInData) { (error) in
if error != nil {
print("Error, Data not saved")
} else {
self.showResAlert(title: "Welcome Back", message: "You are now CHECKED-IN please continue to the rental counter. Thank You.")
}
}
}
#IBAction func callUsTapped(_ sender: Any) {
if let url = URL(string: "tel://\(xxxx)"),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}
extension checkInViewController: CLLocationManagerDelegate{
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locationManager.stopUpdatingLocation()
mapView.showsUserLocation = true
}
}

Find users coordinates with Swift 3 [duplicate]

The delegate Methods of CLLocationManager
didChangeAuthorizationStatus
and
didUpdateToLocation
are not getting called.
Location Always Usage Description key is already added in info.plist and I am getting notification also when i launch app for the first time.
I am able to see the google map, but i am not able to see current location, When i change location, its not getting updated. Basicaaly delegate methods are not getting called.
//code
import UIKit
import GoogleMaps
class ViewController: UIViewController,GMSMapViewDelegate {
#IBOutlet weak var mapViewTest: GMSMapView!
let locationManager = CLLocationManager()
var currentLocation :CLLocation = CLLocation(latitude: 0.0, longitude: 0.0)
var currentLatitude : Double = 0.0
var currentLongitude : Double = 0.0
override func viewDidLoad()
{
super.viewDidLoad()``
locationManager.delegate = self
if (CLLocationManager.locationServicesEnabled())
{
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
// Do any additional setup after loading the view, typically from a nib.
}
}
extension ViewController : CLLocationManagerDelegate
{
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus)
{
if status == .authorizedAlways
{
if(CLLocationManager .locationServicesEnabled())
{
locationManager.startUpdatingLocation()
mapViewTest.isMyLocationEnabled = true
mapViewTest.settings.myLocationButton = true
}
}
}
func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation)
{
mapViewTest.camera = GMSCameraPosition(target: (newLocation.coordinate), zoom: 15, bearing: 0, viewingAngle: 0)
currentLocation = newLocation
currentLatitude = newLocation.coordinate.latitude
currentLongitude = newLocation.coordinate.longitude
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError)
{
print("Errors: " + error.localizedDescription)
}
}
From your code you are working with Swift 3, and in Swift 3 CLLocationManagerDelegate method's signature is changed like this.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
}
//func locationManager(_ manager: CLLocationManager, didUpdateTo newLocation: CLLocation,
from oldLocation: CLLocation) is deprecated with below one
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
Check Apple Documentation on CLLocationManagerDelegate for more details.
After checking your code i found some changes you needs to do as follow,
note : I have only added the code having issue here that of location manager
import UIKit
import CoreLocation
class ViewController: UIViewController {
let locationManager = CLLocationManager()
var currentLocation :CLLocation = CLLocation(latitude: 0.0, longitude: 0.0)
var currentLatitude : Double = 0.0
var currentLongitude : Double = 0.0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
if (CLLocationManager.locationServicesEnabled())
{
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
func locationManager(_ manager: CLLocationManager, didFinishDeferredUpdatesWithError error: Error?) {
print("Errors: " + (error?.localizedDescription)!)
}
}
Also add below lines in .plist file if not added,
<key>NSLocationWhenInUseUsageDescription</key>
<string>$(PRODUCT_NAME) location use</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>$(PRODUCT_NAME) always uses location </string>
Add these two properties in your info.plist
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
you need to put the mapview delegate to self.
try this:
override func viewDidLoad() {
super.viewDidLoad()
// User Location Settings
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
// Google Maps Delegate
mapView.delegate = self
}
// View will appear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Google maps settings
mapView.isMyLocationEnabled = true
mapView.settings.myLocationButton = true
// Get location if autorized
if (CLLocationManager.authorizationStatus() == CLAuthorizationStatus.authorizedWhenInUse) {
let (latitude, longitude) = self.getLocation()
mapView.camera = GMSCameraPosition.camera(
withLatitude: latitude,
longitude: longitude,
zoom: 14)
}
}
//Get the user location
func getLocation() -> (latitude: CLLocationDegrees, longitude: CLLocationDegrees) {
let latitude = (locationManager.location?.coordinate.latitude)!
let longitude = (locationManager.location?.coordinate.longitude)!
return (latitude, longitude)
}

Why can't I output city to a text label, using an action button?

I've set up the location and all in the viewdidload. Pretty much the user will press a button and a label will show their current location (city).
Error: Use of unresolved identifier 'placemark'
func displayLocationInfo(placemark: CLPlacemark) ->String{
self.locationManager.stopUpdatingLocation()
var location:String
location = placemark.locality
println(location)
return location
}
#IBAction func currentLocation(sender: AnyObject) {
originTextField.text = displayLocationInfo(location)
}
That approach can fix your problem:
func displayLocationInfo(placemark:CLLocationCoordinate2D) ->String{
self.locationManager.stopUpdatingLocation()
originTextField.text = ("locations = \(placemark.latitude) \(placemark.longitude)")
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue:CLLocationCoordinate2D = manager.location.coordinate
displayLocationInfo(locValue)
}
#IBAction func currentLocation(sender: AnyObject) {
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}

Can't get location right using Swift

So, I am trying to get my Location inside a function of my ViewController.swift.
The Code I use works when i try it like this:
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var manager : CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue : CLLocationCoordinate2D
locValue = manager.location.coordinate
println("Coordinates = \(locValue.longitude) + \(locValue.latitude)")
manager.stopUpdatingLocation()
}
But what I am trying to do is get it while pressing a button which toggles a function:
var manager : CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyHundredMeters
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue: CLLocationCoordinate2D = manager.location.coordinate
println("locations = \(locValue.longitude) \(locValue.latitude)")
manager.stopUpdatingLocation()
}
#IBAction func refresh() {
getWeatherData()
refreshButton.hidden = true
acitivityIndicatorView.hidden = false
acitivityIndicatorView.startAnimating()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getWeatherData() -> Void {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]!) {
var locValue: CLLocationCoordinate2D = manager.location.coordinate
println("locations = \(locValue.longitude) \(locValue.latitude)")
manager.stopUpdatingLocation()
While using a breakpoint i realized it gets to func locationManager but it jumps to the end of my getweatherdata() function.
I can't see why it doesn't work.
What you are doing is not possible. Inly thing you can do is call manager.startUpdatingLocation() inside refresh() and wait till didUpdateLocations get called with the updated location data.
#IBAction func refresh() {
manager.startUpdatingLocation()
refreshButton.hidden = true
acitivityIndicatorView.hidden = false
activityIndicatorView.hidesWhenStopped = true
acitivityIndicatorView.startAnimating()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
var locValue: CLLocationCoordinate2D = manager.location.coordinate
println("locations = \(locValue.longitude) \(locValue.latitude)")
manager.stopUpdatingLocation()
refreshButton.hidden = false
acitivityIndicatorView.stopAnimating()
}