Core location background update and upload to server
LocationManager Singleton

It is not necessary to use dispatch_once to make LocationService a Singleton.

This pattern can be achieved by doing the following:


Exposing a static type property that creates a new instance of LocationService
Marking the initializer of the class as private


For example:

class LocationService: NSObject, CLLocationManagerDelegate {
    static let shared = LocationSerivce()

    // This class cannot be instantiated outside of this class
    override private init() { 
        // Initialization code
    }
}


shared is lazily instantiated. A performance benefit that you inherit by implementing the Singleton this way.

From Apple’s documentation on Type Properties:


  "Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.”


The private initializer is key to the implementation of the Singleton pattern because it prevents anyone from outside of the class from creating another instance. That said, under other circumstances you may still want instances to be created to give your consumer more choices/functionality.

Ultimately these changes make your code easier to read, ensure you have Singleton and are inline with Apple’s documented approach to Singletons using Swift.

Private CLLocationManager

Your LocationSerivce appears to be a wrapper around Apple’s CLLocationManager class. It would probably be best to mark this constant as private. This prevents outside code from changing the reference or state of your locationManager property.

private let locationManager = CLLocationManager()


Self

In the following functions, the use of self is not required. The reference to locationManager is not ambiguous and self is not required to explicitly state otherwise.

func startUpdatingLocation() {
    print(“Starting Location Updates”)
    self.locationManager.startUpdatingLocation()
}

func stopUpdatingLocation() {
    print(“Stop Location Updates”)
    self.locationManager.stopUpdatingLocation()
}


CLLocationManager Desired Accuracy

You can remove the following code from your initializer:

locationManager.desiredAccuracy = kCLLocationAccuracyBest


On iOS, kCLLocationAccuracyBest is the default value of the desiredAccuracy property.

Accuracy Constants

In terms of accuracy, you have six options:


kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyAccuracyKilometer
kCLLocationAccuracyThreeKilometers


At first glance one may think to use kCLLocationAccuracyBestForNavigation, however because increasing the accuracy requires more device resources (like GPS or Cellular Radio), it also means that more device power will be required. This can have a negative impact on the user experience if expectations are not set. There are also some other caveats that should be understood when setting the  desiredAccuracy property. 

Apple’s desiredAccuracy documentation: https://developer.apple.com/reference/corelocation/cllocationmanager/1423836-desiredaccuracy

When deciding which constant to use, careful consideration will be required based on the app’s intended use and the user’s expectations (and delivering a great mobile experience). I recommend reading the CLLocationManager documentation to better understand its usage and how to strike a good balance between your app’s functionality and device performance.

Apple’s CLLocationManager documentation: https://developer.apple.com/reference/corelocation/cllocationmanager