Decouple iOS code & access location without CoreLocation

Bhuman Soni
Bhuman Soni May 23, 2019
Updated 2020/12/28 at 8:22 AM

To me, thinking of a solution that successfully decouples code is one of the most satisfying aspects of software development. I had that satisfaction recently as I am building a new iOS app that uses CoreLocation. In this post, I will talk about how to decouple iOS code, how to access location without CoreLocation such that you can keep the UIViewController free off a CoreLocation import via delegates. In addition to that, I have also created a little  Github repo to showcase sample code for the solution, read on to get the link to it.


Ever since I have started working with iOS apps, my goal has been to keep the UIViewController code free of any imports other than UIKit and Foundation. I could successfully accomplish that for the most part, except when it came to working with CoreLocation. For some reason, every solution I came up with, I had to include an “import CoreLocation” in the UIViewController which was against what I wanted.


First the personal reason,

In case anyone reading this is thinking, why do I want to achieve this (i.e. decouple code)? The main reason, well I am just lazy, writing the same code again and again is a little boring. Also being the only programmer in my startup means, I have to do all the coding so I just want to avoid re-writing the same code where possible.

Now for an emotionless, more technically sound explanation with examples

Say, if we have a code base (or app) where we can get the user’s location, physical address etc with a simple function call to a LocationHelper class. Then we can do that in in any ViewController or any other class, we don’t care how the location class gets the location as long as we know we will get the location. This means that we can use Apple, Google, Bing Maps or change our method of acquiring the solution without affecting our ViewController code. Lastly, this also means that we can use our LocationHelper class in any app that needs that functionality by importing the LocationHelper code.

Decouple iOS code

To get the location in iOS, you need to start updating location from a CLLocationManager class after which you get the location coordinates in CLLocationManagerDelegate.didUpdateLocations method. My problem was, even if I wrote a LocationHelper class with a method that calls CLLocationManager.startUpdatingLocation() how do I get the location information from the  CLLocationManagerDelegate without importing a CoreLocation class.

All this time, there was an obvious solution that I simply didn’t see i.e. Delegates.

Delegate pattern

One way of thinking about Delegate pattern is to think of it as an alternative to inheritance. It’s when you delegate the responsibility of achieving something to someone else i.e. for an object to communicate back to it’s parent object. hmm maybe I am not clear? I know what this is, but I can’t think of a “layman’s terms” English explanation for it right now.

The delegate pattern is heavily used in iOS and knowingly or unknowingly every iOS developer has to have used it. For example, UITableViewDelgate, UITextViewDelegate, CLLocationManagerDelegate etc etc. This is why I cannot believe I did not think of this solution sooner! Actually, I can believe that, I had been so occupied with all things Product Management at my startup, that I was unable to just sit-down and give this careful thought.

Delegates with Protocol

A Protocol in Swift is what an interface is in Java i.e. a blue print for methods and properties of a class. In Swift we can also use them to implement Delegate pattern e.g. let’s have a look at the protocol for our solution

protocol LocationUpdatesDelegate {
    func locationUpdated(lat: Double, lon: Double)

So when the location is updated, it notifies all the classes that adopt that protocol with the latest location. Let’s see how we use the Protocol, first in the LocationHelper class

var locationManager: CLLocationManager? = nil
var locationUpdatesDelegate: LocationUpdatesDelegate?

override init() {

    locationManager = CLLocationManager()
    locationManager!.delegate = self
//MARK: Location manager delegate methods
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    for location in locations {
        let lat = location.coordinate.latitude
        let lon = location.coordinate.longitude
        locationUpdatesDelegate?.locationUpdated(lat: lat, lon: lon)

In the CLLocationManagerDelgate method as soon as we get the location, we call the locationUpdated method of our delegate by passing in the latest coordinates. Next, let’s look at the UIViewController  that adopts that Protocol

import UIKit
class ViewController: UIViewController, LocationUpdatesDelegate {
    var locationHelper: LocationHelper? = nil
    override func viewDidLoad() {
        locationHelper = LocationHelper()
        locationHelper?.locationUpdatesDelegate = self
        // Do any additional setup after loading the view.
    func locationUpdated(lat: Double, lon: Double) {}

As you can see our ViewController conforms to our LocationUpdatesDelegate and implements it’s locationUpdated method. Notice, how the lat and lon parameters are of type Double, and not CLLocationCoordinate2D? This is just to keep our UIViewController free of any CoreLocation import. See, UIKit is the only import in our UIViewController class. What happens in the locationUpdated method is explained below.

Like the blog? Subscribe for updates

The physical address

Okay, one last thing, there’s some simple code in that Github repo, that I should explain. Once we get the latitude (lat) and longitude (lon) of the user location, how do we get the physical address of the user? I have defined a struct just for convenience in the LocationHelper called Address

struct Address {
    //setting them as optional because
    //sometimes the GeoCoder cannot find
    //these from a placemark
    var name: String? = nil
    var postCode: String? = nil
    var locality: String? = nil
    var city: String? = nil
    var country: String? = nil
    var state: String? = nil //could be state or province

    func toString() -> String {
        if let n = name,
            let cty = city,
            let ctry = country {
            return "\(n), \(cty) (\(ctry))"
        return "\(name ?? ""), \(locality ?? ""), \(city ?? ""), \(state ?? ""),  \(postCode ?? "") \(country ?? "")"

We use Address , as a return type in the getCoordinateAddress completion handler.

func getCoordinateAddress(lat: Double, lon: Double, completion: @escaping (_ address: Address?) -> ()) {
    let location = CLLocation(latitude: lat, longitude: lon)
    CLGeocoder().reverseGeocodeLocation(location) { (placemarks, error) in
        if error != nil {
        if let placesFound = placemarks {
            for place in placesFound {
                var address = Address()
       = place.locality
                address.postCode = place.postalCode
                address.state = place.administrativeArea

A delegate could potentially be used for this too but for this one, we don’t need to. I mean the completion handler works just fine. Lastly, here’s how we use that in our UIViewController

class ViewController: UIViewController, LocationUpdatesDelegate {        
    @IBOutlet var locationLbl: UILabel!
    var address: Address? = nil {
        willSet {
            locationLbl.text = newValue?.toString()
    func locationUpdated(lat: Double, lon: Double) {
        locationHelper?.getCoordinateAddress(lat: lat, lon: lon, completion: { (reverseGeocodedAddress) in
            if reverseGeocodedAddress != nil {
                self.address = reverseGeocodedAddress

The above code is self explanatory, as we just use one of Swift’s property observer to se the text for a UILabel.


That’s a wrap! You can find all the code for this post on this Github repository here. Have a look at the LocationHelper class, you could jus re-use it or use as a starting point in your iOS app. Give that Github repo a star if you find it useful.

Like the blog? Subscribe for updates

As usual, if you find any of my posts useful support me by  buying or even trying one of my apps on the App Store.

Also, if you can leave a review on the App Store or Google Play Store, that would help too.

Share this Article
Leave a comment

Leave a Reply

Your email address will not be published.

Ads Blocker Image Powered by Code Help Pro

Ads Blocker Detected!!!

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

Powered By
Best Wordpress Adblock Detecting Plugin | CHP Adblock