swiftswift3

Does Swift allow passing argument based on control flow like if else?


I am trying to if else condition when passing argument.

getLocation(with:
            if #available(iOS 14.0, *) {
                coreLocation.authorizationStatus
            } else {
                CLLocationManager.authorizationStatus()
            }
        )


func getLocation(with authorizationStatus: CLAuthorizationStatus) {
    
    if authorizationStatus == .authorizedWhenInUse || authorizationStatus == .authorizedAlways {
        coreLocation.requestLocation() // Fetch location
    }
    else if authorizationStatus == .denied {
        let alertController = UIAlertController(title: "Error", message: "Location is disabled, please provide your city manually.", preferredStyle: .actionSheet)
        let okAction = UIAlertAction(title: "OK", style: .default)
        alertController.addAction(okAction)
        present(alertController, animated: true, completion: nil)
    }
    else {
        coreLocation.requestWhenInUseAuthorization() // Ask permission
    }
    
}

However I am getting this error 'if' may only be used as expression in return, throw, or as the source of an assignment.


Solution

  • Normally, you can use the ternary operator:

    getLocation(with: someCondition ? coreLocation.authorizationStatus : CLLocationManager.authorizationStatus())
    

    However, this does not work with #available. #available can only appear after if, while, guard.

    if statements, as you have discovered, can only be used as expressions when it is a return value, a thrown error, or on the right hand side of an assignment. SE-0380 addresses this design decision:

    This proposal chooses a narrow path of only enabling expressions in the 3 cases laid out at the start. This is intended to cover the vast majority of use cases, but could be followed up by expanded functionality covering many other use cases. Further cases could be added in later proposals once the community has had a chance to use this feature in practice – including source breaking versions introduced under a language variant.

    So the answer is "no", for now.

    I would do something like this to avoid writing getLocation twice.

    let authStatus = if #available(iOS 14.0, *) {
        coreLocation.authorizationStatus
    } else {
        CLLocationManager.authorizationStatus()
    }
    getLocation(with: authStatus)