Reputation: 4726
I've implemented a singleton object for CoreLocation's location manager for an app I'm developing using the class constant method for Swift 1.2 and above explained here.
Although when I try to access the currentLocation
variable either directly or using the getter method, I get nil
.
What am I missing?
Implementation
import Foundation
import CoreLocation
class LocationService: NSObject, CLLocationManagerDelegate {
static let sharedInstance = LocationService()
var locationManager: CLLocationManager!
var currentLocation: CLLocationCoordinate2D!
var currentDirection: StepDirection!
private override init() {
super.init()
locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.headingFilter = kCLHeadingFilterNone
locationManager.distanceFilter = 1
}
// MARK: Control Methods
func startUpdatingLocation() {
locationManager.startUpdatingLocation()
print("Location updates are started.")
}
func stopUpdatingLocation() {
locationManager.stopUpdatingLocation()
print("Location updates are stopped.")
}
func startUpdatingHeading() {
locationManager.startUpdatingHeading()
print("Compass updates are started.")
}
func stopUpdatingHeading() {
locationManager.stopUpdatingHeading()
print("Compass updates are stopped.")
}
// MARK: CoreLocation Location Updates
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// If location data can be determined
if let location = locations.last! as CLLocation! {
currentLocation = location.coordinate
// print("Current Location: \(currentLocation)")
NSNotificationCenter.defaultCenter().postNotificationName("LocationUpdate", object: self,
userInfo: ["longitude": currentLocation.longitude,
"latitude": currentLocation.latitude])
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Location Manager: \(error)")
NSNotificationCenter.defaultCenter().postNotificationName("LocationUpdateError", object: self,
userInfo: nil)
}
// MARK: CoreLocation Heading Updates
func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
let trueHeading = newHeading.trueHeading
var declanation = (newHeading.trueHeading - newHeading.magneticHeading)
declanation = 50.0
if (0.0+declanation <= trueHeading) && (trueHeading <= 90.0+declanation) {
currentDirection = StepDirection.Right
} else if (90.0+declanation < trueHeading) && (trueHeading <= 180.0+declanation) {
currentDirection = StepDirection.Down
} else if (180.0+declanation < trueHeading) && (trueHeading <= 270.0+declanation) {
currentDirection = StepDirection.Left
} else if (270.0+declanation < trueHeading) && (trueHeading <= 360.0+declanation) {
currentDirection = StepDirection.Up
}
NSNotificationCenter.defaultCenter().postNotificationName("CompassUpdate", object: self, userInfo: ["currentDirection": currentDirection.rawValue])
}
func locationManagerShouldDisplayHeadingCalibration(manager: CLLocationManager) -> Bool {
return true
}
// MARK: Access Methods
func getCurrentLocation() -> CLLocationCoordinate2D! {
return currentLocation
}
}
Access
I first tried accessing it like the following:
LocationService.sharedInstance.currentLocation
or LocationService.sharedInstance.getCurrentLocation
I then assigned the shared instance to a variable thinking that I wasn't preserving the state:
locationService = LocationService.sharedInstance
And then using the access methods or the variable names:
locationService.currentLocation
or locationService.getCurrentLocation
Upvotes: 0
Views: 124
Reputation: 6800
You need to call your startUpdating function to get the location manager to start updating the location.
private override init() {
super.init()
locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.headingFilter = kCLHeadingFilterNone
locationManager.distanceFilter = 1
locationManager.startUpdatingLocation()
}
As you asked in comments, the location manager will continuously attempt to get a user's location until stop updating is called.
Discussion This method returns immediately. Calling this method causes the location manager to obtain an initial location fix (which may take several seconds) and notify your delegate by calling its locationManager:didUpdateLocations: method. After that, the receiver generates update events primarily when the value in the distanceFilter property is exceeded. Updates may be delivered in other situations though. For example, the receiver may send another notification if the hardware gathers a more accurate location reading.
You can read more here: https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/#//apple_ref/occ/instm/CLLocationManager/startUpdatingLocation
You can access new location data from the delegate method using the location property of the location manager (which you already do in your delegate method).
Upvotes: 1