Implement Location Services Using SWIFT

In previous posts I talked about How to write SWIFT code to make HTTP GET request and How to implement NSURLSession delegate using SWIFT. On these simple concepts I started developing a prototype project to use OpenWeatherMap API. Yes, there are plenty of weather related applications available. I wanted to pick some topic for prototype that could demonstrate use of various network programming concepts using SWIFT.

To find weather related data based on the location of service, it is essential that you have means to find current location of user and know when user changes its location. iOS provides location services to get user's location. In this post I will show how to use iOS location services using SWIFT. Apple has provided wonderful documentation on this topic and some code snippets implemented in Objective-C. You can find this documentation at following location.

Core objects for location service

At the heart of location service is CLLocationManager class. This object provides the means to configure the service. The object provides means to start and stop location service. This object communicates location changes related events through CLLocationManagerDelegate. You will implement a class that implements CLLocationManagerDelegate protocol. You don't have to implement all the functions of protocol. You can implement the ones that you will need. For example if you are not developing for iBeacons then you can skip implementing protocol methods dealing with location for beacons.

Pre-requisites

Update Property Info List File

Starting iOS8 it is required that you enter following entries in your property info list file e.g info.plist.

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

These two entries display text in pop-up that comes up for user to permission to use location services on design. The following is an example of how these may look like in file.

    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Application will access location service when in use</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Application will use location services when running in background</string>

Link to CoreLocation framework

To use location service classes, your project should link to CoreLocation.framework. Open your project's settings and add the reference. Following screenshot shows how it will look in your project settings.

CoreLocation framework reference

Import CoreLocation

Make sure that you import CoreLocation in each class files that are going to use location service related object.

CLLocationManagerDelegate Implementation

Following code shows sample implementation of delegate. It implements getting only location update events.

    import Foundation
    import CoreLocation
    public class LocationServiceManager:NSObject,CLLocationManagerDelegate{
    static let sharedInstance = LocationServiceManager()
    var locationManager:CLLocationManager?
    var locationUpdateSubscribers:Dictionary<String, (([CLLocation])->Void)>?
    private override init(){
        super.init()
        self.locationUpdateSubscribers = Dictionary<String, (([CLLocation])->Void)>()
        self.locationManager = CLLocationManager()
        self.locationManager!.delegate = self;
        self.locationManager!.desiredAccuracy = kCLLocationAccuracyKilometer
        self.locationManager!.distanceFilter = 500 // meters
        self.locationManager!.requestWhenInUseAuthorization()
        self.locationManager!.startUpdatingLocation()
    }

    public func subscribeLocationUpdates(uniqueId id:String,
        notificationHandler:([CLLocation])->Void){
        self.locationUpdateSubscribers![id] = notificationHandler
    }

    public func unsubscribeLocationUpdates(uniqueId id:String){
        if let _ = locationUpdateSubscribers![id]{
            locationUpdateSubscribers!.removeValueForKey(id)
        }
    }

    public func locationManager(manager: CLLocationManager,
        didFailWithError error: NSError){
        print("Location service failure: \(error.description)")
    }

    public func locationManager(manager: CLLocationManager,
        didUpdateLocations locations: [CLLocation]){
        print("Location service locations updated: \(locations)")
        // Send notification to all subscribers.
        for(_,handler) in self.locationUpdateSubscribers!{
            handler(locations)
        }
    }

    public func locationManager(manager: CLLocationManager,
        cdidVisit visit: CLVisit){
        print("Location manager visit event: \(visit.description)")
    }
}

There are two important things to notice in this implementation. Before starting location service you should call requestWhenInUseAuthorization method on your CLLocationManager object. After that you can call startUpdatingLocation method to start the service. If you fail to update property information list or call requestWhenInUseAuthorization method, your delegate will not receive any location updates. The framework does not throw any errors when you try to start location service without above updates. It can be little frustrating at times to not get any error or warnings. This delegate allows multiple client to register for notifications.

Getting user location

Following code snippet shows how this location service manager is used to get location.

    @IBAction func connectToNetwork() {
        var locManager = LocationServiceManager.sharedInstance
        locManager.subscribeLocationUpdates(uniqueId: "Main", notificationHandler: locationsUpdated)
    }

    func locationsUpdated(locations:[CLLocation]){
        print("\(locations.count) location updates received")
        for location in locations{
            apiClient.getWeather(geoLocation: location, completionHandler: gotWeatherFromCity)
        }
    }
    
    func gotWeatherFromCity(weatherData: WeatherData, error: ApiError?){
        print(weatherData.rawData)
    }

In subsequent posts I will show how this location service implementation will be integrated with rest of the project to update user interface.

comments powered by Disqus

Blog Tags