Видеокурсы по изучению языка программирования Swift. Подробнее

Опциональная последовательность как альтернатива принудительному извлечению

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

Вы обозначаете опциональную последовательность, когда ставите вопросительный знак (?) опционального значения, свойство, метод или индекс которого вы хотите вызвать, если опционал не nil. Это очень похоже на установку восклицательного знака (!) после опционального значения для принудительного извлечения его значения. Основное отличие в том, что опциональная последовательность не исполняется, если опционал равен nil, в то время как принудительное извлечение приводит к runtime ошибке, когда опционал равен nil.

Факт того, что опциональная последовательность может быть вызвана и на значение nil, отражается в том, что результатом работы опциональной последовательности всегда является опциональная величина, даже в том случае, если свойство, метод или сабскрипт, к которым вы обращаетесь, возвращает неопциональное значение. Вы можете использовать это значение опционального возврата для проверки успеха (если возвращенный опционал содержит значение) или неудачи (если возвращенное значение опционала nil).

В частности, результат вызова опциональной последовательности того же типа, что и тип ожидаемого возвращаемого значения, только в завернутом в опционал виде. Свойство, которое обычно возвращало Int, вернет Int?, когда обращаются к нему через опциональную последовательность.

Следующие несколько фрагментов кода покажут вам как отличаются опциональная последовательность от принудительного извлечения, и как она позволяет вам проверить значение на успех.

Первые два класса Person, Residence определены как:

class Person {
    var residence: Residence?
}
 
class Residence {
    var numberOfRooms = 1
}

Экземпляры Residence имеют единственное свойство numberOfRooms типа Int, со значением по умолчанию 1. Экземпляры Person имеют опциональное свойство residence типа Residence?.

Если вы создаете новый экземпляр Person, то его свойство residence по умолчанию имеет значение nil, в силу того, что оно является опционалом. В коде ниже john имеет свойство residence, значение которого nil:

let john = Person()

Если вы попытаетесь получить доступ к свойству numberOfRooms свойства residence экземпляра Person, поставив восклицательный знак после residence, для принудительного извлечения, то вы получите ошибку исполнения, потому что residence не имеет значения для извлечения:

let roomCount = john.residence!.numberOfRooms
// ошибка runtime

Код, представленный выше, срабатывает успешно, если john.residence имеет не nil значение и устанавливает корректное значение типа Int для roomCount. Однако этот код всегда всегда будет выдавать ошибку исполнения, когда residence равен nil, что указано выше.

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

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Выведет "Unable to retrieve the number of rooms."

Это сообщает Swift “сцепиться” с опциональным свойством residence и получить значение numberOfRooms, если residence существует.

Так как попытка доступа к numberOfRooms имеет потенциальную возможность претерпеть неудачу, то опциональная последовательность возвращает значение типа Int? или “опциональный Int”. Когда residence равен nil, в примере выше, этот опциональный Int также будет nil, для отображения того факта, что было невозможно получить доступ к numberOfRooms.

Обратите внимание, что это верно даже если numberOfRooms неопциональный Int. Факт того, что запрос был через опциональную последовательность означает, что вызов numberOfRooms будет всегда возвращать Int?, вместо Int.

Вы можете присвоить экземпляр Residence в john.residence, так что оно больше не будет являться значением nil.

john.residence = Residence()

Теперь john.residence содержит экземпляр Residence, а не nil. Если вы попытаетесь получить доступ к numberOfRooms с той же последовательностью опционала, что и раньше, то теперь она вернет нам Int?, который содержит значение по умолчанию numberOfRooms равное 1:

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// Выведет "John's residence has 1 room(s)."
Swift: 
3.0