Logo 61e73bc61c0e1780102320e879dc3cac0e29303ea8894dd8f10c942f3ba8120f

otters.io

An adorable little blog

Getting Started with CoreLocation in Swift

Tuesday — May 24th, 2016

Location

You want to get a user’s location in your app but aren’t sure where to find it. You’ve heard of CoreLocation but aren’t sure where to start and old StackOverflow answers have you tinkering with plists all day.

Don’t fret though! Working with CoreLocation in Swift is simple once you get set up. In case you missed the memo, CoreLocation is Apple’s framework for accessing a user’s location and heading (with their permission of course!).

Before we get rolling, there are a few disclaimers I need to get out of the way. I’ll be using iOS 9 and this code won’t work with iOS 7 or lower and it won’t work in Playgrounds. There is a way to get CoreLocation in Swift on iOS 7 but it requires using respondsToSelector and I’m far too snobby to do that if it isn’t required.

With that out of the way, let’s get started with a new Single View Application in Xcode. Before we write any code we’ll have to fiddle with our Info.plist file.

Corelocation info plist

To the right of the Information Property List heading, we’ll need to click the “➕” to add a new key and manually enter the name NSLocationAlwaysUsageDescription and then another named NSLocationWhenInUseUsageDescription both of type String. The values for these keys should be a short description for why your app needs the user’s location.

Location permission dialog box

You may have seen dialog boxes in other apps with a tiny message that asks for your location and that’s what we’re setting here.

That’s all the more meddling we need to do in the Info.plist file. Now we can actually start using CoreLocation in our app!

In the ViewController.swift file that Xcode so graciously provided for you, we’ll import CoreLocation, create a location manager property, and make our View Controller the location manager’s delegate.

That looks something like this in your ViewController:


import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
  let manager = CLLocationManager()

  override func viewDidLoad() {
    super.viewDidLoad()
    manager.delegate = self
  }
}

Before we can read the user’s location we need to ask permission politely. So we’ll check if the user has given us permission yet, and if not, we’ll ask for it. In our case, we’ll ask for permission to use the user’s location when our app is in use, but you could also use the location manager's requestAlwaysAuthorization method to request access when the app is in the background. We can update the viewDidLoad method to include this:


override func viewDidLoad() {
  super.viewDidLoad()
  manager.delegate = self

  if CLLocationManager.authorizationStatus() == .NotDetermined {
    manager.requestWhenInUseAuthorization()
  }
}

Finally, we need to implement the locationManagerDidChangeAuthorizationStatus and locationManagerDidUpdateLocations delegate methods so we know when the user has given us the go-ahead and when the location manager has information for us. So we’ll add the following methods to our view controller:


func locationManager(manager: CLLocationManager,
  didChangeAuthorizationStatus status: CLAuthorizationStatus) {

  manager.startUpdatingLocation()
}

func locationManager(manager: CLLocationManager,
  didUpdateToLocation newLocation: CLLocation,
  fromLocation oldLocation: CLLocation) {

  print(newLocation)
}

And that’s it! When you build and run the app, you should be prompted for permission to access your location. If you allow it, the app will start printing your location as CoreLocation gets new information. The next step might be moving the location manager and delegate out of the View Controller but this example works for getting started.

You can see the full view controller code here.


Universal Self in Swift 3

Saturday — April 30th, 2016

Do you have any static methods on your classes or structs? Normally to call those, you’d have to write:

MySuperFancyExampleClass.staticMethod()

If you were referencing something's type inside an instance method you've had the option of saying self.dynamicType instead of the full class name which can be a bit shorter in certain cases. For example:

extension MySuperFancyExampleClass {
    func someInstanceMethod() {
        self.dynamicType.staticMethod()
    }
}

Universal Self

What is dynamic, besides a terribly overused marketing term? dynamicType grabs the runtime type of whatever is asking for it and returns it as a value you can work with. In plain English, it gives you back the type of a thing.

Coming soon to a Swift near you is the ability to be even lazier! Thanks to a newly accepted proposal by Erica Sadun for a “Universal Self” we'll be able to access these methods using the keyword Self (capital ‘S’).

extension MySuperFancyExampleClass {
    func someInstanceMethod() {
        Self.staticMethod()
    }
}

The usage makes sense; little ‘s’ self for the instance, big ‘S’ Self for the type. This is poised to replace the dynamicType keyword entirely in Swift 3. Another neat time saver that tidies up the language is a win in my book.


A Successor to successor()

Thursday — April 28th, 2016

Array

Changes are heading towards collection types in Swift 3! Yesterday, the big man himself approved a proposal to rethink how collections and indices interact in Swift 3. The gist of it being: If you want to get the index of a thing in a collection, ask the collection, not another index.

To give some background on what this will affect, let’s look at how the system works right now. In Swift 2, Indices have to keep track of not only where they are but how the whole collection is structured so they can give you the next or previous index. That is hard to optimize.

In Swift 3, since collections know their structure already, the proposal is to let them traverse themselves. You want the index of an object? Ask the collection it’s in. You want the following index? Ask the collection. The previous? Ask the collection. Easy for humans to understand and easier for the optimizer to optimize.

Most existing code will remain unscathed and not need to be updated. If you have code that gets indices from other indices, such as index.successor() and index.predecessor(), you will need to change to getting an index from the collection. When Swift 3 comes out, the change should look something like this:

// Before:
let luckyNumbers = [42, 7, 13, 33, 25]
var index = luckyNumbers.startIndex
let nextIndex = index.successor()

// After:
let luckyNumbers = [42, 7, 13, 33, 25]
var index = luckyNumbers.startIndex
let nextIndex = luckyNumbers.index(after: index)

This change reads easier by my eyes. More importantly, because it keeps information about the structure of the collection in the logic of the collection, indices don’t need to keep tabs on what your collection type looks like. 👍