1
\$\begingroup\$

I've recently began trying to put more error handling in to my code so I thought I'd post a use-case to check I'm on the right path. I feel like this is going to make my functions much larger and more indented/nested than before. Is this the right way to go about things or should I be utilising try? instead? Where do people generally put these Error enum definitions?

fileprivate enum LocationError: Error {
    case noAuthorization
    case noBeaconSupport
    case rangingUnavailable
}

class ViewController: UIViewController, CLLocationManagerDelegate {
    @IBOutlet weak var distanceReading: UILabel!
    var locationManager: CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()

    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.requestWhenInUseAuthorization()

    view.backgroundColor = UIColor.gray
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    do {
        guard status == .authorizedWhenInUse else {
            throw LocationError.noAuthorization
        }
        guard CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) else {
            throw LocationError.noBeaconSupport
        }
        guard CLLocationManager.isRangingAvailable() else {
            throw LocationError.rangingUnavailable
        }
        startScanning()
    }
    catch LocationError.noAuthorization {
        print("User has not authorized us to use location")
    }
    catch LocationError.noBeaconSupport {
        print("User's device does not support Beacons")
    }
    catch LocationError.rangingUnavailable {
        print("User's device does not support ranging")
    }
    catch {
        fatalError()
    }
}
\$\endgroup\$
1
\$\begingroup\$

Throwing Swift errors is a mechanism how a function/method can report a failure to its caller. Your code throws and catches the error within the same method, and I can see no advantage of using try/catch in that situation. Your code is equivalent to

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    guard status == .authorizedWhenInUse else {
        print("User has not authorized us to use location")
        return
    }
    guard CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) else {
        print("User has not authorized us to use location")
        return
    }
    guard CLLocationManager.isRangingAvailable() else {
        print("User's device does not support ranging")
        return
    }
    startScanning()
}

which is

  • shorter and easy to understand,
  • makes the enum LocationError obsolete (which is fileprivate, and therefore apparently not used anywhere else),
  • makes the catch-all with fatalError() obsolete.

I would even go a step further: guard is useful in connection with optional binding (to avoid the "optional binding pyramid of doom"). In your case, the same can be achieved with a simple if/else if/.../else statement:

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    if status != .authorizedWhenInUse {
        print("User has not authorized us to use location")
    } else if !CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
        print("User has not authorized us to use location")
    } else if !CLLocationManager.isRangingAvailable() {
        print("User's device does not support ranging")
    } else {
        startScanning()
    }
}
\$\endgroup\$
  • \$\begingroup\$ Thanks. In what case would I want to use Error and try catch? When I do more than just print? \$\endgroup\$ – Declan McKenna Dec 8 '17 at 14:15
  • \$\begingroup\$ @Deco: A function throws an Error to report a failure to its caller. You use try/catch when calling functions that throw an Error. \$\endgroup\$ – Martin R Dec 8 '17 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.