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
}