Как правильно сделать Nil Coalescing в Swift?

Предполагается сделать так

var inputField =  UITextField()
let defaultText = "PLACEHOLDER"
let newText = inputField.text!.isEmpty ? defaultText : inputField.text!
let newText2 = inputField.text ?? defaultText

newText работает и выводит PLACEHOLDER,

Но newText только показывает "" в окне предварительного просмотра в Swift

Зачем? Как сделать это правильно?

2 ответа

Есть большая разница между "" а также nil, Ваш text свойство пустое, но это не nil, (Это на самом деле равно строке "".) Таким образом, ваша проверка .isEmpty работает, но ваша попытка слиться не сработает. Это, с другой стороны, будет работать:

let text: String? = nil
let newText2 = text ?? defaultText

Итак, ваше понимание слияния ноль в порядке; Ваше предположение, что пустое текстовое поле возвращает nil is not: фактически возвращает пустую - но существующую - строку.

import UIKit

var inputField =  UITextField()
inputField.text?.isEmpty // true !!!
// by deafault it is empty, so i set it
inputField.text = "default text"

let defaultText = "PLACEHOLDER"
let newText = inputField.text?.isEmpty == true ? defaultText : inputField.text!
let newText2 = inputField.text ?? defaultText

print(newText)  // default text
print(newText2) // default text

в вашем фрагменте newText2 пустая строка, потому что inputField.text не ноль

безопасный способ, как это сделать (inputField.text может быть ноль, пустой или некоторый текст)

import UIKit

var inputField =  UITextField()
let defaultText = "PLACEHOLDER"
if let txt = inputField.text {
    inputField.text = txt.isEmpty ? defaultText : txt
}

let newText = inputField.text ?? defaultText

print(inputField.text, newText) // Optional("PLACEHOLDER") PLACEHOLDER

В результате, если inputField.text пуст или равен nil, ему присваивается некоторое значение по умолчанию, в противном случае текст не изменяется

Более быстрое решение для проверки ":x empty или nil?"- использовать расширение:

extension Optional where Wrapped == String {
    var nilIfEmpty: String? {
        guard let strongSelf = self else {
            return nil
        }
        return strongSelf.isEmpty ? nil : strongSelf
    }

    var isEmptyOrNil: Bool {
        guard let strongSelf = self else {
            return true
        }
        return strongSelf.isEmpty
    }
}

Причина let newText2 = inputField.text ?? defaultText терпит неудачу потому что inputField.text = "" по умолчанию, что не попадает в nil случай оператора nil-coalescing (как Optional("") != nil).


Вы можете использовать эти Optional<String> расширения для замены:

let newText = inputField.text!.isEmpty ? defaultText : inputField.text!
let newText2 = inputField.text ?? defaultText

с

let newText = inputField.text.isEmptyOrNil ? defaultText : inputField.text! 
let newText2 = inputField.text.nilIfEmpty ?? defaultText

оба работают правильно. Хотя я бы рекомендовал безопасно развернутьinputField.text вместо использования ! оператор (хотя это технически безопасно, я стараюсь по возможности избегать использования оператора взрыва) - отсюда и решение nil-coalescing, использующее nilIfEmpty предпочтительнее.

Кроме того, вы можете использовать последнее, чтобы предотвратить распространенное (и беспорядочное) someOptionalString?.isEmpty ?? true танцевать в операторах if и тернарных операциях, как:

if someOptionalString.isEmptyOrNil {
    // Do something when a string is empty or nil...
}

намного чище, чем

if someOptionalString?.isEmpty ?? true {
    // Do something when a string is empty or nil...
}
Другие вопросы по тегам