how to represent nil Error Swift completion block

1.3k Views Asked by At

Hi I have a web service worker object in swift that passes a completion block to the caller view controller. The code is as follows:

func getFlightData(for airportCode: String, minutesBehind:String, minutesAhead:String, completion: (([Flight], NSError) -> Void)?) {
    var urlComponents = URLComponents()
    urlComponents.scheme = "https"
    urlComponents.host = "xxxxxxx.com"
    urlComponents.path = "/1/airports/"+airportCode+"/flights/flightInfo"
    urlComponents.queryItems = [
        URLQueryItem(name: "city", value: airportCode),
        URLQueryItem(name: "minutesBehind", value: minutesBehind),
        URLQueryItem(name: "minutesAhead", value: minutesAhead)

    ]

    guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("xxxxxxxxx", forHTTPHeaderField: "Authorization")
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)


    let task = session.dataTask(with: request) { (responseData, response, responseError) in
        DispatchQueue.main.async {


            if let error = responseError {

                //completion block???


            }

            else if let jsonData = responseData {

                let decoder = JSONDecoder()

                do {
                    let posts = try decoder.decode([Flight].self, from: jsonData)
                    //completion?(posts, nil) ???? what to pass for Error? Successful call
                } catch {
                    self.showError()

                }
            }

            else {
                //completion block???
                self.showError()
            }
        }
    }
    task.resume()
}

whatvalues do I pass in the completion blocks Error parameter when call is successful. I cant pass nil as swift does not let me do that. Can someone suggest a better way to make this API call? How to send completion block etc.

2

There are 2 best solutions below

6
Charles Srstka On

Declare the completion block as taking an Error? instead of an NSError, and then you will be able to pass nil to it in the success case. The ? is what makes the parameter optional, which makes it possible for it to contain nil. (Also, use Error instead of NSError, as it is the idiomatic Swift error type).

Alternatively, you can have your completion block take a Result enum, which you can define like this:

public enum Result<T> {
    case success(T)
    case error(Error)

    public func unwrap() throws -> T {
        switch self {
        case let .success(ret):
            return ret
        case let .error(error):
            throw error
        }
    }
}

You can then use either the .success or .error cases, depending on whether the operation succeeded or failed.

4
GIJOW On

It doesn't accept nil because your parameter NSError isn't optional.

Declare you method signature like

func getFlightData(for airportCode: String, minutesBehind:String, minutesAhead:String, completion: (([Flight], NSError?) -> Void)?) {

....

}

And it should work