nil и опциональные типы

Последнее обновление: 29.12.2017

Опциональные типы представляют объекты, которые могут иметь, а могут и не иметь значение. Опциональные типы выступают двойниками базовых типов. Все они имеют в конце вопросительный знак: Int?, String? и т.д. Вопросительный знак как раз указывает, что это опциональный тип.

Например, рассмотрим следующую ситуацию:

let someString = "123"
let someNumber = Int(someString)

Здесь инициализатор Int(someString) преобразует строку someString в число. В данном случае у нас все нормально, так как строка "123" действительно содержит число 123. Однако, что, если бы переменная someString представляла бы строку "hello"? В этом случае инициализатор не смог бы преобразовать строку в число. Поэтому инициализатор возвращает не просто объект Int, а Int?, то есть объект, который может иметь, а может не иметь значения.

По факту, если объект не имеет значения, то ему присваивается специальное значение nil. В коде мы также можем установить явным образом это значение:

var number: Int? = 12
number = nil	// теперь переменная number не имеет значения

Значение nil может применяться только к объектам опциональных типов.

Фактически запись типа Int? является сокращением от Optional<Int>. То есть мы также можем определить переменную следующим образом:

var number: Optional<Int> = 12

Несмотря на то, что в примере выше переменной number присваивается число 12, но фактически переменная будет иметь в качестве значения Optional(12), то есть мы могли бы написать следующим образом:

var number : Optional<Int>= Optional(12)
// или так
var number2 = Optional(12)

При этом опять же стоит понимать, что Optional<Int>, это не то же самое, что и Optional<String> или Optional<Doublegt;, например:

var number = Optional(12)
number = Optional("12") // Ошибка number представляет тип Optional<Int>, а не Optional<String>

Получение значения из Optional

При работе с объектами опциональных типов следует помнить, что они не эквивалентны объектам обычных типов. То есть следующий пример у нас работать не будет:

var a: Int? = 12
var b: Int = 10
var c = a + b	// ошибка - разные типы

a и b здесь переменные разных типов, хотя казалось бы обе переменных хранят целые числа. И чтобы полноценно работать с объектами опциональных типов, следует извлечь из них значение. Для извлечения значения используется оператор ! - восклицательный знак после названия объекта опционального типа. Данный оператор еще называют unwrap operator или forced unwrap operator:

var a: Int? = 12
var b: Int = 10
var c = a! + b		// с = 22

Другой пример:

var b: Int = 10
var a: Int? = Int("123")
b = a! + b
print(a!)    // 123
print(b)    // 133

Неявное получение значений Optional

Swift предоставляет еще один способ получения значения подобных типов, который заключается в использовании типов Optional с неявно получаемым значением (implicitly unwrapped Optional):

var b: Int = 10
var a: Int! = Int("123")
b = a + b
print(a)    // 123
print(b)    // 133

Здесь переменная a имеет тип Int!, а не Int?. Фактиччески это тот же самый Optional, но теперь нам явным образом не надо применять оператор ! для получения его значения.

Проверка Optional на nil

В то же время если переменная a в примере выше не будет содержать конкретное значение, то программа опять же выбросит ошибку. Например? в случае var a: Int! = Int("abc") или var a: Int? = Int("abc"). Поэтому перед использованием объектов опциональных типов желательно проверить, что они имеют какие-либо значение.

Для проверки мы можем использовать условную конструкцию if. Ее общая форма:

if var переменная | let константа = опциональное_значение {
	действия1
} else {
	действия2
}

Если опциональное_значение не равно nil, то оно присваивается создаваемой переменной (или константе), и выполняются действия1. Иначе выполняются действия2.

Например:

var str: String = "123"
var b: Int = 10
if var a = Int(str){
	a+=b
	print(a)
}
else{
	print(b)
}

Если выражение Int(str) (которое возвращает объект Int?) успешно преобразует строку в число, то есть будет иметь значение, то создается переменная a, которой присваивается полученное значение, и затем выполняется код:

a+=b
print(a)

Если же преобразование из строки в число завершится с ошибкой, и выражение Int(str) возвратит значение nil, то выполняется код в блоке else:

else{
	print(b)
}

Но также в данном случае мы могли и по другому проверить на значение nil:

var str: String = "123"
var b: Int = 10
var a: Int? = Int(str)
if a != nil {
	a+=b
	print(a)
}
else{
	print(b)
}

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

let a = Int("123")
let b = Int("456")
if let aVal = a, let bVal = b{
    print(aVal)
    print(bVal)
}
else{
    print("Error")
}

В данном случае выражение if выполняется, если и a, и b не равны nil. Иначе выполняется блок else.

Сравнение объектов Optional

При сравнении объекта Optional с объектом конкретного типа, Swift преобразует объект конкретного типа к типу Optional:

let a: Int? = 10
if a == 10{
    print("a is equal to 10")
}
else{
    print("a is not equal to 10")
}

И таким образом работают операции == и !=. Однако с операциями <, >, <=, >= все будет несколько иначе. Например, следующий код выдаст ошибку:

let a: Int? = 10
if a > 5{
    print("a is greater than 5")
}

И в подобных операциях к объекту Optional необходимо применить оператор !:

let a: Int? = 10
if a != nil && a! > 5{
    print("a is greater than 5")
}

Optional в switch..case

Если сравниваемое значение в конструкции switch представляет объект Optional, то с помощью операции ? мы можем получить и сравнивать его значение при его наличии:

let i = Int("1")
switch i {
case 1?:
    print("i is equal to 1")
case let n?:
    print("i is equal to \(n)")
case nil:
    print("i is undefined")
}

Оператор nil-объединения

Оператор ?? позволяет проверить значения объекта Optional на nil. Этот оператор принимает два операнда a ?? 10. Если первый операнд не равен nil, то возвращается значение первого операнда. Если первый операнд равен nil, то возвращается второй операнд:

let a = Int("234")
let b = a ?? 10
print(b)	// 234

В данном случае поскольку константа a не равна nil, то выражение a ?? 10 возвращает значение этой константы, то есть число 234.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850