Bird
Raised Fist0
iOS Swiftmobile~20 mins

Location services (Core Location) in iOS Swift - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Location Tracker
This screen shows the user's current latitude and longitude using Core Location. It updates the location when the user moves.
Target UI
-------------------------
| Location Tracker       |
|-----------------------|
| Latitude: ---.------   |
| Longitude: ---.------  |
|                       |
| [Start Tracking]       |
-------------------------
Request user permission for location access when the app runs
Show current latitude and longitude on screen
Add a button labeled 'Start Tracking' that starts updating location
Update latitude and longitude labels as location changes
Handle permission denied by showing an alert
Starter Code
iOS Swift
import UIKit
import CoreLocation

class LocationTrackerViewController: UIViewController {
    let locationManager = CLLocationManager()

    let latitudeLabel = UILabel()
    let longitudeLabel = UILabel()
    let startButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        // Setup UI
        latitudeLabel.text = "Latitude: ---.------"
        longitudeLabel.text = "Longitude: ---.------"
        startButton.setTitle("Start Tracking", for: .normal)

        latitudeLabel.translatesAutoresizingMaskIntoConstraints = false
        longitudeLabel.translatesAutoresizingMaskIntoConstraints = false
        startButton.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(latitudeLabel)
        view.addSubview(longitudeLabel)
        view.addSubview(startButton)

        NSLayoutConstraint.activate([
            latitudeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            latitudeLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100),

            longitudeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            longitudeLabel.topAnchor.constraint(equalTo: latitudeLabel.bottomAnchor, constant: 20),

            startButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            startButton.topAnchor.constraint(equalTo: longitudeLabel.bottomAnchor, constant: 40)
        ])

        // TODO: Add your code here
    }
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
iOS Swift
import UIKit
import CoreLocation

class LocationTrackerViewController: UIViewController, CLLocationManagerDelegate {
    let locationManager = CLLocationManager()

    let latitudeLabel = UILabel()
    let longitudeLabel = UILabel()
    let startButton = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        latitudeLabel.text = "Latitude: ---.------"
        longitudeLabel.text = "Longitude: ---.------"
        startButton.setTitle("Start Tracking", for: .normal)

        latitudeLabel.translatesAutoresizingMaskIntoConstraints = false
        longitudeLabel.translatesAutoresizingMaskIntoConstraints = false
        startButton.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(latitudeLabel)
        view.addSubview(longitudeLabel)
        view.addSubview(startButton)

        NSLayoutConstraint.activate([
            latitudeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            latitudeLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100),

            longitudeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            longitudeLabel.topAnchor.constraint(equalTo: latitudeLabel.bottomAnchor, constant: 20),

            startButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            startButton.topAnchor.constraint(equalTo: longitudeLabel.bottomAnchor, constant: 40)
        ])

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest

        startButton.addTarget(self, action: #selector(startTracking), for: .touchUpInside)

        checkLocationAuthorization()
    }

    func checkLocationAuthorization() {
        switch CLLocationManager.authorizationStatus() {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .restricted, .denied:
            showPermissionDeniedAlert()
        case .authorizedWhenInUse, .authorizedAlways:
            // Permission granted, do nothing yet
            break
        @unknown default:
            break
        }
    }

    @objc func startTracking() {
        if CLLocationManager.locationServicesEnabled() {
            locationManager.startUpdatingLocation()
        } else {
            showPermissionDeniedAlert()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        guard let location = locations.last else { return }
        latitudeLabel.text = String(format: "Latitude: %.6f", location.coordinate.latitude)
        longitudeLabel.text = String(format: "Longitude: %.6f", location.coordinate.longitude)
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        checkLocationAuthorization()
    }

    func showPermissionDeniedAlert() {
        let alert = UIAlertController(title: "Location Permission Denied", message: "Please enable location permissions in Settings to use this feature.", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default))
        present(alert, animated: true)
    }
}

This app uses Core Location to get the user's current position. We first ask for permission to access location data. If permission is denied, we show an alert to inform the user.

The startButton triggers location updates. When the location changes, the delegate method updates the latitude and longitude labels with the new coordinates.

We use CLLocationManagerDelegate to handle location updates and authorization changes. The UI is simple and centered, showing the coordinates clearly.

Final Result
Completed Screen
-------------------------
| Location Tracker       |
|-----------------------|
| Latitude: 37.774929   |
| Longitude: -122.419416|
|                       |
| [Start Tracking]       |
-------------------------
User taps 'Start Tracking' button
App requests location permission if not granted
If permission granted, latitude and longitude update live as user moves
If permission denied, alert appears explaining how to enable permissions
Stretch Goal
Add a 'Stop Tracking' button that stops location updates and resets labels
💡 Hint
Add another UIButton below the start button. When tapped, call locationManager.stopUpdatingLocation() and reset labels to default text.

Practice

(1/5)
1.

What is the main purpose of CLLocationManager in iOS apps?

easy
A. To request and receive location updates from the device
B. To display maps on the screen
C. To manage user notifications
D. To handle network requests

Solution

  1. Step 1: Understand the role of CLLocationManager

    CLLocationManager is designed to get location data from the device's GPS or other sources.
  2. Step 2: Differentiate from other classes

    Displaying maps is done by MKMapView, notifications by UNUserNotificationCenter, and network requests by URLSession.
  3. Final Answer:

    To request and receive location updates from the device -> Option A
  4. Quick Check:

    CLLocationManager = Location updates [OK]
Hint: CLLocationManager is for getting location, not showing maps [OK]
Common Mistakes:
  • Confusing CLLocationManager with map display classes
  • Thinking it handles notifications or networking
  • Assuming it works without user permission
2.

Which of the following is the correct way to declare a CLLocationManager instance in Swift?

?
easy
A. locationManager = CLLocationManager()
B. var locationManager: CLLocationManager
C. let locationManager = CLLocationManager()
D. CLLocationManager locationManager = new CLLocationManager()

Solution

  1. Step 1: Recall Swift instance creation syntax

    In Swift, to create an instance, use let variable = ClassName() or var variable = ClassName().
  2. Step 2: Check each option

    let locationManager = CLLocationManager() correctly creates a constant instance. var locationManager: CLLocationManager declares a variable without initialization, which is incomplete. locationManager = CLLocationManager() misses declaration keyword. CLLocationManager locationManager = new CLLocationManager() uses incorrect syntax from other languages.
  3. Final Answer:

    let locationManager = CLLocationManager() -> Option C
  4. Quick Check:

    Swift instance creation = let variable = Class() [OK]
Hint: Use let or var with = ClassName() to create instances [OK]
Common Mistakes:
  • Forgetting to initialize the variable
  • Using syntax from other languages like Java or C#
  • Missing let or var keyword
3.

Given the following Swift code snippet, what will be printed when the location updates?

class LocationHandler: NSObject, CLLocationManagerDelegate {
  let manager = CLLocationManager()
  override init() {
    super.init()
    manager.delegate = self
    manager.requestWhenInUseAuthorization()
    manager.startUpdatingLocation()
  }
  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.first {
      print("Lat: \(location.coordinate.latitude), Lon: \(location.coordinate.longitude)")
    }
  }
}
let handler = LocationHandler()
medium
A. It crashes due to missing delegate method
B. It prints the latitude and longitude of the first location update
C. It prints nothing because delegate is not set
D. It prints an error message about missing permissions

Solution

  1. Step 1: Analyze delegate setup and method

    The delegate is set to self, and the required method locationManager(_:didUpdateLocations:) is implemented to print coordinates.
  2. Step 2: Understand permission and update calls

    The code requests permission and starts location updates, so when location is available, it prints latitude and longitude.
  3. Final Answer:

    It prints the latitude and longitude of the first location update -> Option B
  4. Quick Check:

    Delegate set + method implemented = prints location [OK]
Hint: Delegate method prints first location coordinates on update [OK]
Common Mistakes:
  • Assuming delegate is not set
  • Thinking permission request blocks printing
  • Missing delegate method causes crash
4.

What is wrong with this Swift code snippet for requesting location updates?

let locationManager = CLLocationManager()
locationManager.startUpdatingLocation()
medium
A. It is missing setting the delegate and requesting user permission
B. startUpdatingLocation() is not a valid method
C. locationManager must be declared as a class, not a constant
D. The code should call stopUpdatingLocation() first

Solution

  1. Step 1: Check for permission request

    The code does not request user permission, which is required before starting location updates.
  2. Step 2: Check delegate assignment

    Without setting a delegate, the app cannot receive location updates callbacks.
  3. Final Answer:

    It is missing setting the delegate and requesting user permission -> Option A
  4. Quick Check:

    Permission + delegate needed before updates [OK]
Hint: Always request permission and set delegate before updates [OK]
Common Mistakes:
  • Calling startUpdatingLocation without permission
  • Not assigning delegate to receive updates
  • Thinking startUpdatingLocation is invalid
5.

You want your app to get the user's location only once and then stop updates to save battery. Which code snippet correctly does this?

class SingleLocationFetcher: NSObject, CLLocationManagerDelegate {
  let manager = CLLocationManager()
  override init() {
    super.init()
    manager.delegate = self
    manager.requestWhenInUseAuthorization()
    manager.startUpdatingLocation()
  }
  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.first {
      print("Got location: \(location.coordinate.latitude), \(location.coordinate.longitude)")
      manager.stopUpdatingLocation()
    }
  }
}
hard
A. This code will crash because stopUpdatingLocation is not a valid method
B. This code will never stop updates because stopUpdatingLocation is called too early
C. This code requests background location permission incorrectly
D. This code correctly stops updates after receiving the first location

Solution

  1. Step 1: Check when stopUpdatingLocation is called

    The method locationManager(_:didUpdateLocations:) calls stopUpdatingLocation() after receiving the first location, stopping further updates.
  2. Step 2: Verify permission and delegate setup

    The code requests 'when in use' authorization and sets the delegate properly, so it will work as intended.
  3. Final Answer:

    This code correctly stops updates after receiving the first location -> Option D
  4. Quick Check:

    Stop updates inside didUpdateLocations = single fetch [OK]
Hint: Call stopUpdatingLocation inside didUpdateLocations after first fix [OK]
Common Mistakes:
  • Calling stopUpdatingLocation before receiving location
  • Confusing background permission with when-in-use
  • Not setting delegate before starting updates
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard