В Swift 2, как я могу вернуть JSON ошибки синтаксического анализа в блок завершения?
Я хотел бы создать функцию в Swift 2, которая получает данные из URL-адреса и возвращает его как объект JSON, используя NSURLSession. Сначала это выглядело довольно прямолинейно. Я написал следующее:
func getJson(url:NSURL, completeWith: (AnyObject?,NSURLResponse?,NSError?)->Void) -> NSURLSessionTask? {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {
(data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
if error != nil {
completeWith(nil, response, error)
}
if let data = data {
do {
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
} catch let caught as NSError {
completeWith(nil, response, caught)
}
completeWith(object, response, nil)
} else {
completeWith(nil, response, error)
}
}
return task
}
Однако это не скомпилируется, потому что блок завершения не объявляет "броски". Точная ошибка Cannot invoke 'dataTaskWithURL' with an argument list of type '(NSURL, (NSData?, NSURLResponse?, NSError?) throws -> Void)'
. Несмотря на то, что я обнаружил все ошибки в своем выражении do/catch
, Swift по-прежнему хочет распространять NSError в цепочке. Единственный способ, который я вижу вокруг, - использовать try!
, например:
if let data = data {
let object:AnyObject? = try! NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
completeWith(object, response, nil)
} else {
completeWith(nil, response, error)
}
Теперь все компилируется просто отлично, но я потерял NSError, который был добавлен NSJSONSerialization.JSONObjectWithData
.
Я могу захватить NSError, потенциально выброшенным NSJSONSerialization.JSONObjectWithData
, и передать его в блок завершения без изменения сигнатуры блока завершения?
Ответы
Ответ 1
Я думаю, ваш улов не исчерпывающий, поэтому вам нужно что-то вроде этого:
do
{
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
completeWith(object, response, nil)
} catch let caught as NSError {
completeWith(nil, response, caught)
} catch {
// Something else happened.
// Insert your domain, code, etc. when constructing the error.
let error: NSError = NSError(domain: "<Your domain>", code: 1, userInfo: nil)
completeWith(nil, nil, error)
}
Ответ 2
чтобы ответить на вопрос от Jguffey. Я видел ту же ошибку, когда я попытался вызвать функцию следующим образом:
let taskResult = getJson(url!) {
(any: AnyObject,resp: NSURLResponse,error: NSError) in
он должен выглядеть следующим образом:
let taskResult = getJson(url!) {
(any: AnyObject?,resp: NSURLResponse?,error: NSError?) in
Ответ 3
NSJSONSerialization выбрасывает тип ErrorType, а не NSError.
поэтому правильный код будет
do {
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
} catch let caught as ErrorType {
completeWith(nil, response, caught)
}
Вы также меняете свою подпись метода на ErrorType.
По этой причине принятый ответ всегда войдет в блок "что-то еще случилось" и никогда не сообщит об ошибке, вызванной NSJSONSerialization.JSONObjectWithData.