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

Понижающее приведение

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

Константа или переменная определенного класса может фактически ссылаться на экземпляр подкласса. Чему вы будете верить в данном случае, вы можете попробовать привести тип к типу подкласса при помощи оператора понижающего приведения (as? или as!).

Из-за того, что понижающее приведение может провалиться, оператор приведения имеет две формы. Опциональная форма (as?), которая возвращает опциональное значение типа, к которому вы пытаетесь привести. И принудительная форма (as!), которая принимает попытки понижающего приведения и принудительного разворачивания результата в рамках одного составного действия.

Используйте опциональную форму оператора понижающего приведения (as?), когда вы не уверены, что ваше понижающее приведение выполнится успешно. В этой форме оператор всегда будет возвращать опциональное значение, и значение будет nil, если понижающее приведение будет не выполнимо. Так же это позволяет вам проверить успешность понижающего приведения типа.

Используйте принудительную форму оператора понижающего приведения (as!), но только в тех случаях, когда вы точно уверены, что понижающее приведение будет выполнено успешно. Эта форма оператора вызовет ошибку исполнения, если вы попытаетесь таким образом привести к некорректному типу класса.

Пример ниже перебирает элементы MediaItem в массиве library и выводит соответствующее описание для каждого элемента. Чтобы сделать это, ему нужно получить доступ к каждому элементу как Movie или Song, а не просто как к MediaItem. Это необходимо для того, чтобы был доступ к свойствам director, artist, которые пригодятся нам в описании.

В этом примере каждый элемент массива может быть либо Movie, либо Song. Вы не знаете наперед какой класс вам нужно использовать для каждого элемента, так что логично будет использовать опциональную форму оператора понижающего приведения (as?) для проверки возможности понижающего приведения к конкретному подклассу конкретного элемента массива:

for item in library {
    if let movie = item as? Movie {
        print("Movie: '\(movie.name)', dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: '\(song.name)', by \(song.artist)")
    }
}
 
// Movie: 'Casablanca', dir. Michael Curtiz
// Song: 'Blue Suede Shoes', by Elvis Presley
// Movie: 'Citizen Kane', dir. Orson Welles
// Song: 'The One And Only', by Chesney Hawkes
// Song: 'Never Gonna Give You Up', by Rick Astley

Пример начинается с попытки понижающего приведения текущего элемента item в качестве Movie. Так как item является экземпляром MediaItem, то этот элемент может быть Movie, но он и так же может быть и Song или даже просто базовым MediaItem. Из-за этой неопределенности мы и используем опциональную форму оператора (as?). Результат выражения item as? Movie является тип Movie? или “опциональный Movie”.

Понижающее приведение к Movie проваливается, когда оно применимо к экземплярам Song в массиве library. Объединив это все, мы получаем, что пример выше использует опциональную привязку для проверки наличия значения у опционального Movie (то есть, чтобы выяснить успешность проведенной операции). Опциональная привязка записана выражением вида “if let movie = item as? Movie”, что может быть прочитано так:

“Пробуем получить доступ к item в качестве Movie. Если доступ успешен, то присвоим временную константу movie значению, которое мы получили из опционального Movie.”

Если понижающее приведение прошло успешно, то свойства movie используются в качестве вывода описания для экземпляра Movie, включая имя director. Аналогичный принцип используется при проверке экземпляров Song и при выводе описания (включая имя artist), как только находится элемент Song в массиве library.

Заметка

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

 

Swift: 
3.0