Быстрая проверка идиоматических ошибок

Допустим, у вас есть такая функция:

func getSomething(error: NSErrorPointer) -> Something

и вы обычно используете его следующим образом:

var error : NSError? = nil
let a = getSomething(&error)

Какой идиоматический способ проверить ошибку здесь? Более конкретные вопросы:

  1. Если error == nil, можем ли мы предположить, что a никогда не будет равно нулю, и наоборот?
  2. Что мы должны проверить в первую очередь: error (на его нуль) или a (чтобы убедиться, что это не ноль)?
  3. Может ли a != nil && error != nil быть правдой в некоторых случаях?

Благодарю вас!


person mikejd    schedule 01.04.2015    source источник


Ответы (2)


Сравните Обработка объектов ошибок, возвращаемых методами в "Руководстве по программированию обработки ошибок":

Важно! Успех или неудача указываются возвращаемым значением метода. Хотя методы Cocoa, которые косвенно возвращают объекты ошибок в домене ошибок Cocoa, гарантированно возвращают такие объекты, если метод указывает на сбой, напрямую возвращая nil или NO, вы всегда должны проверять, что возвращаемое значение равно nil или NO, прежде чем пытаться что-либо сделать с Объект NSError.

Поэтому для методов Cocoa/Cocoa Touch вы всегда должны сначала проверять возвращаемое значение. Гарантируется, что error != nil в случае сбоя метода, но явно не гарантируется, что error == nil в случае успеха метода.

Примеры:

Сериализация JSON

var error : NSError?
if let jsonObj = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &error) {
    // success
} else {
    // failure
    println("Invalid JSON data: \(error!.localizedDescription)")
}

Запрос на получение основных данных

var error : NSError?
if let result = context.executeFetchRequest(request, error: &error) {
    // success, result has zero or more elements
} else {
    // failure
    println("Fetch failed: \(error!.localizedDescription)")
}

Копирование файлов

var error : NSError?
if !NSFileManager.defaultManager().copyItemAtPath(srcPath, toPath: dstPath, error: &error) {
    println("Cannot copy file: \(error!.localizedDescription)")
}

Конечно, вы можете определить свои собственные правила для своих собственных функций, но я бы следовал тем же рекомендациям Apple.


Обновление: в Swift 2 методы Cocoa, которые вызывают ошибки, преобразуются в функции Swift, которые вызывают ошибку, и эта ошибка должна обрабатываться с помощью try-catch. Вот версия приведенных выше примеров для Swift 2:

Сериализация JSON

do {
    let jsonObj = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    // success
} catch let error as NSError {
    // failure
    print("Invalid JSON data: \(error.localizedDescription)")
}

Запрос на получение основных данных

do {
    let result = try context.executeFetchRequest(request)
    // success, result has zero or more elements
} catch let error as NSError {
    // failure
    print("Fetch failed: \(error.localizedDescription)")
}

Копирование файлов

do {
    try NSFileManager.defaultManager().copyItemAtPath(srcPath, toPath: dstPath)
} catch let error as NSError {
    print("Cannot copy file: \(error.localizedDescription)")
} 
person Martin R    schedule 01.04.2015
comment
Мартин, спасибо за отличный ответ! Вы хоть представляете, какая мотивация стоит за этой логикой? Почему сначала нужно проверить возвращаемое значение, а не ошибку? - person mikejd; 01.04.2015
comment
@mikejd: я думаю некоторое время назад слышал/читал, что функция может передать указатель ошибки другой функции более низкого уровня, которая завершается сбоем и устанавливает ошибку. Если функция более высокого уровня решает проигнорировать эту ошибку функции более низкого уровня и возвращает успех, то объект ошибки все равно устанавливается. Но я не уверен на 100%, и я действительно не наблюдал этот случай. - person Martin R; 01.04.2015
comment
Хм, звучит вполне разумно. - person mikejd; 01.04.2015

если функция возвращает необязательное значение, т.е.

func someFunc(someVar: String) -> NSData? {
  // some code
}

(необязательный параметр означает, что он может возвращать ноль), тогда проверка ошибок довольно проста

if let data = someFunc("someString") {
  // this means there was NO error as the function didn't return a nil
}
else {
  // This means there was an error
}

Это видео является довольно хорошим справочником по проверке и обработке ошибок в swift https://youtu.be/m8szaLqHVDs.

person Mladen Kajic    schedule 14.09.2015
comment
Хотя возвращаемое значение nil может быть хорошим намеком на сбой, вам также часто нужна фактическая ошибка, чтобы понять, что именно пошло не так, не так ли? - person mikejd; 19.09.2015
comment
Это зависит и весьма субъективно. но если функция предоставляет доступ к указателю NSError в качестве параметра, вы можете использовать его или нет. - person Mladen Kajic; 19.09.2015