Swift: варианты тестирования для nil

Я использую Xcode 6 Beta 4. У меня такая странная ситуация, когда я не могу понять, как правильно тестировать дополнительные опции.

Если у меня есть необязательный xyz, это правильный способ тестирования:

if (xyz) // Do something

или

if (xyz != nil) // Do something

В документах говорится, что сделать это первым способом, но я обнаружил, что иногда требуется второй путь и не генерирует ошибку компилятора, но в других случаях второй способ генерирует ошибку компилятора.

В моем конкретном примере используется синтаксический анализатор XML GData с быстрым переходом:

let xml = GDataXMLDocument(
    XMLString: responseBody,
    options: 0,
    error: &xmlError);

if (xmlError != nil)

Здесь, если я только что сделал:

if xmlError

он всегда будет возвращать true. Однако, если я это сделаю:

if (xmlError != nil)

тогда он работает (как работает в Objective-C).

Есть ли что-то с XML-GData и как он обрабатывает варианты, которые мне не хватает?

Ответ 1

В Xcode Beta 5 они больше не позволяют вам делать:

var xyz : NSString?

if xyz {
  // Do something using 'xyz'.
}

Это приводит к ошибке:

не соответствует протоколу BooleanType.Protocol

Вы должны использовать одну из этих форм:

if xyz != nil {
   // Do something using 'xyz'.
}

if let xy = xyz {
   // Do something using 'xy'.
}

Ответ 2

Чтобы добавить к другим ответам вместо назначения переменной с именованной переменной внутри условия if:

var a: Int? = 5

if let b = a {
   // do something
}

вы можете повторно использовать одно и то же имя переменной:

var a: Int? = 5

if let a = a {
    // do something
}

Это может помочь вам избежать исчерпания имен переменных объявлений...

Это использует переменную затенение, которая поддерживается в Swift.

Ответ 3

Один из самых прямых способов использования опций - это следующее:

Предполагая, что xyz имеет необязательный тип, например Int?.

if let possXYZ = xyz {
    // do something with possXYZ (the unwrapped value of xyz)
} else {
    // do something now that we know xyz is .None
}

Таким образом, вы можете проверить, если xyz содержит значение, и если да, немедленно работайте с этим значением.

Что касается ошибки вашего компилятора, тип UInt8 не является необязательным (примечание no '?') и поэтому не может быть преобразован в nil. Убедитесь, что переменная, с которой вы работаете, является необязательной, прежде чем рассматривать ее как одну.

Ответ 4

Swift 3.0, 4.0

В основном существует два способа проверки необязательного значения для nil. Вот примеры сравнения между ними

1. если пусть

if let - самый простой способ проверить опцию для nil. Другие условия могут быть добавлены к этой проверке nil, разделенной запятой. Переменная не должна быть nil для перемещения для следующего условия. Если требуется только проверка nil, удалите дополнительные условия в следующем коде.

Кроме этого, если x не равно nil, будет закрыто if, и x_val будет доступно внутри. В противном случае срабатывает замыкание else.

if let x_val = x, x_val > 5 {
    //x_val available on this scope
} else {

}

2. охранник пусть

guard let может делать подобные вещи. Основная цель - сделать его логически более разумным. Это как сказать. Убедитесь, что переменная не равна нулю, иначе остановите функцию. guard let также может выполнять дополнительную проверку условий как if let.

Различия заключаются в том, что развернутое значение будет доступно в той же области, что и guard let, как показано в комментарии ниже. Это также приводит к тому, что при закрытии else программа должна выйти из текущей области, return, break и т.д.

guard let x_val = x, x_val > 5 else {
    return
}
//x_val available on this scope

Ответ 5

Из быстрого программирования руководство

Если утверждения и принудительная развязка

Вы можете использовать оператор if, чтобы узнать, содержит ли опциональный стоимость. Если опция имеет значение, оно имеет значение true; если оно не имеет значения вообще, он вычисляет false.

Итак, лучший способ сделать это -

// swift > 3
if xyz != nil {}

и если вы используете инструкцию xyz in if.Then вы можете распаковать xyz в оператор if в постоянной переменной. Поэтому вам не нужно разворачивать каждое место в инструкции if, где используется xyz.

if let yourConstant = xyz{
      //use youtConstant you do not need to unwrap `xyz`
}

Это соглашение предлагается apple, за ним последуют разработчики.

Ответ 6

Хотя вы все равно должны либо явно сравнивать необязательный параметр с nil, либо использовать необязательную привязку для дополнительного извлечения его значения (т.е. опционные значения неявно преобразуются в логические значения), стоит заметить, что Swift 2 добавил guard statement, чтобы избежать пирамиды doom при работе с несколькими необязательными значения.

Другими словами, теперь ваши параметры теперь явно проверяют на nil:

if xyz != nil {
    // Do something with xyz
}

Дополнительное связывание:

if let xyz = xyz {
    // Do something with xyz
    // (Note that we can reuse the same variable name)
}

А guard:

guard let xyz = xyz else {
    // Handle failure and then exit this code block
    // e.g. by calling return, break, continue, or throw
    return
}

// Do something with xyz, which is now guaranteed to be non-nil

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

if let abc = abc {
    if let xyz = xyz {
        // Do something with abc and xyz
    }        
}

Вы можете избежать этого вложения с помощью операторов guard:

guard let abc = abc else {
    // Handle failure and then exit this code block
    return
}

guard let xyz = xyz else {
    // Handle failure and then exit this code block
    return
}

// Do something with abc and xyz

Ответ 7

Вместо if, тройной оператор может пригодиться, когда вы хотите получить значение, основанное на том, что-то не равно:

func f(x: String?) -> String {
    return x == nil ? "empty" : "non-empty"
}

Ответ 8

Другой подход, помимо использования операторов if или guard для выполнения необязательной привязки, заключается в расширении Optional с помощью:

extension Optional {

    func ifValue(_ valueHandler: (Wrapped) -> Void) {
        switch self {
        case .some(let wrapped): valueHandler(wrapped)
        default: break
        }
    }

}

ifValue получает замыкание и вызывает его со значением в качестве аргумента, когда необязательный параметр не равен нулю. Он используется следующим образом:

var helloString: String? = "Hello, World!"

helloString.ifValue {
    print($0) // prints "Hello, World!"
}

helloString = nil

helloString.ifValue {
    print($0) // This code never runs
}

Вероятно, вы должны использовать if или guard, поскольку это самые обычные (так знакомые) подходы, используемые программистами Swift.

Ответ 9

Одна из опций, которая не была специально рассмотрена, - это использование синтаксиса игнорируемых значений Swift:

if let _ = xyz {
    // something that should only happen if xyz is not nil
}

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

Ответ 10

var xyz : NSDictionary?

// case 1:
xyz = ["1":"one"]
// case 2: (empty dictionary)
xyz = NSDictionary() 
// case 3: do nothing

if xyz { NSLog("xyz is not nil.") }
else   { NSLog("xyz is nil.")     }

Этот тест работал как ожидалось во всех случаях. BTW, вам не нужны скобки ().

Ответ 11

Теперь вы можете быстро сделать следующее, что позволит вам немного восстановить objective-c if nil else

if textfieldDate.text?.isEmpty ?? true {

}

Ответ 12

Если у вас есть условие и вы хотите развернуть и сравнить, как насчет использования оценки короткого замыкания сложного булевого выражения, как в

if xyz != nil && xyz! == "some non-nil value" {

}

Конечно, это не так читаемо, как некоторые другие предлагаемые сообщения, но выполняет свою работу и несколько лаконично, чем другие предлагаемые решения.

Ответ 13

Также вы можете использовать Nil-Coalescing Operator

nil-coalescing operator (a ?? b) разворачивает необязательный a, если он содержит значение a, или возвращает значение по умолчанию a b, если a равно nil. Выражение a всегда имеет необязательный тип. Выражение b должно соответствовать типу, который хранится в a.

let value = nullableValue ?? defaultValue

Если nullableValue равен nil, он автоматически присваивает значение defaultValue

Ответ 14

Расширение протокола Swift 5

Вот подход, использующий расширение протокола, так что вы можете легко встроить дополнительную проверку nil:

 public extension Optional {

    var isNil: Bool {

        guard case Optional.none = self else {
            return false
        }

        return true

    }

}

Usage

Usage
var myValue: String?

if !myValue.isNil {
    // do something
}