как представить блок завершения nil Error Swift

Привет, у меня есть рабочий объект веб-службы в Swift, который передает блок завершения контроллеру представления вызывающей стороны. Код выглядит следующим образом:

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()
}

какие значения я передаю в блоке завершения. Параметр ошибки при успешном вызове. Я не могу пройти nil, так как Swift не позволяет мне это сделать. Может ли кто-нибудь предложить лучший способ сделать этот вызов API? Как отправить блок завершения и т. д.


person Ackman    schedule 28.03.2018    source источник


Ответы (2)


Он не принимает nil, потому что ваш параметр NSError не является необязательным.

Объявите свою подпись метода, например

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

....

}

И это должно работать

person GIJOW    schedule 28.03.2018
comment
Не используйте NSError; протокол Error более гибкий и более идиоматичен для Swift. - person Charles Srstka; 29.03.2018
comment
Это не вопрос, и я не знаю остальной части его реализации. Если он использует NSError может быть какая-то причина - person GIJOW; 29.03.2018
comment
NSError соответствует Error, поэтому все, что принимает Error, может принимать NSError. Нет причин использовать NSError в Swift API. - person Charles Srstka; 29.03.2018
comment
Предположим... да... все еще не зная и просто отвечая на его вопрос - person GIJOW; 29.03.2018

Объявите блок завершения как принимающий Error? вместо NSError, и тогда вы сможете передать ему nil в случае успеха. ? делает параметр необязательным, что позволяет ему содержать nil. (Кроме того, используйте Error вместо NSError, так как это идиоматический тип ошибки Swift).

В качестве альтернативы вы можете сделать так, чтобы ваш блок завершения принимал перечисление Result, которое вы можете определить следующим образом:

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
        }
    }
}

Затем вы можете использовать случаи .success или .error, в зависимости от того, была ли операция успешной или неудачной.

person Charles Srstka    schedule 28.03.2018
comment
Готово! Как насчет моих ответных данных? Как мне это отправить? В случае ошибки? - person Ackman; 29.03.2018
comment
@Ackman Тип Result предназначен для случаев, когда данные ответа и ошибки являются взаимоисключающими. Если вы хотите прочитать данные ответа даже при получении ошибки, придерживайтесь реализации кортежа, но используйте Error? вместо NSError. - person Charles Srstka; 29.03.2018
comment
Я сделал это, можете ли вы показать мне в моем коде, как внести эти изменения? Я все еще в замешательстве. Должен ли я сохранить ошибку? или сохранить Result в моем блоке завершения. Я новичок в Swift, и мне трудно обдумать это. - person Ackman; 29.03.2018
comment
Если вы хотите иметь возможность передавать данные ответа и ошибку, сделайте то же самое, но замените NSError на Error?. Вы можете использовать это точно так же, как и раньше, за исключением того, что теперь вы можете передавать nil без ошибок компилятора. Если получение ошибки означает, что данные ответа не имеют значения (распространенный случай), вместо этого используйте перечисление Result для передачи либо ответа , либо ошибки. - person Charles Srstka; 29.03.2018
comment
В своем ответе вы сказали (также используйте NSError вместо Error, так как это идиоматический тип ошибки Swift). Разве вы не хотели сказать (Кроме того, используйте Error вместо NSError, так как это идиоматический тип ошибки Swift)? - person Duncan C; 29.03.2018
comment
@DuncanC Действительно, это была опечатка. Теперь исправлено. - person Charles Srstka; 29.03.2018