Spec-Zone .ru
спецификации, руководства, описания, API

Библиотека разработчика XCode

Разработчик

Swift язык программирования

iBook
На этой странице

Преобразование типа

Преобразование типа является способом проверить тип экземпляра и/или обработать тот экземпляр, как будто это - различный суперкласс или подкласс от где-то в другом месте в его собственной иерархии классов.

Преобразование типа в Swift реализовано с is и as операторы. Эти два оператора обеспечивают простой и выразительный способ проверить тип значения или бросить значение к другому типу.

Можно также использовать преобразование типа, чтобы проверить, соответствует ли тип протоколу, как описано в Проверке Соответствие Протокола.

Определение иерархии классов для преобразования типа

Можно использовать преобразование типа с иерархией классов и подклассов, чтобы проверить тип определенного экземпляра класса и бросить тот экземпляр к другому классу в той же иерархии. Эти три фрагмента кода ниже определяют иерархию классов и массива, содержащего экземпляры тех классов для использования в примере преобразования типа.

Первый отрывок определяет новый вызванный базовый класс MediaItem. Этот класс обеспечивает основную функциональность для любого вида элемента, появляющегося в библиотеке цифровых сред. В частности это объявляет a name свойство типа String, и init name инициализатор. (Предполагается, что все элементы носителей, включая все фильмы и песни, будут иметь имя.)

  • class MediaItem {
  • var name: String
  • init(name: String) {
  • self.name = name
  • }
  • }

Следующий отрывок определяет два подкласса MediaItem. Первый подкласс, Movie, инкапсулирует дополнительную информацию о фильме или фильме. Это добавляет a director свойство поверх основы MediaItem класс, с соответствующим инициализатором. Второй подкласс, Song, добавляет artist свойство и инициализатор поверх базового класса:

  • class Movie: MediaItem {
  • var director: String
  • init(name: String, director: String) {
  • self.director = director
  • super.init(name: name)
  • }
  • }
  • class Song: MediaItem {
  • var artist: String
  • init(name: String, artist: String) {
  • self.artist = artist
  • super.init(name: name)
  • }
  • }

Заключительный отрывок создает постоянный вызванный массив library, который содержит два Movie экземпляры и три Song экземпляры. Тип library массив выведен путем инициализации его с содержанием литерала массивов. Средство проверки типа Swift в состоянии вывести это Movie и Song имейте общий суперкласс MediaItem, и таким образом, это выводит тип [MediaItem] для library массив:

  • let library = [
  • Movie(name: "Casablanca", director: "Michael Curtiz"),
  • Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
  • Movie(name: "Citizen Kane", director: "Orson Welles"),
  • Song(name: "The One And Only", artist: "Chesney Hawkes"),
  • Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
  • ]
  • // the type of "library" is inferred to be [MediaItem]

Элементы, сохраненные в library тихи Movie и Song экземпляры негласно. Однако, если Вы выполняете итерации по содержанию этого массива, элементы, которые Вы получаете назад, вводятся как MediaItem, и не как Movie или Song. Для работы с ними как их собственный тип необходимо проверить их тип, или нисходящий их к другому типу, как описано ниже.

Проверка типа

Используйте оператора проверки типа (is) проверять, имеет ли экземпляр определенный тип подкласса. Оператор проверки типа возвращается true если экземпляр имеет тот тип подкласса и false если это не.

Пример ниже определяет две переменные, movieCount и songCount, которые считают число Movie и Song экземпляры в library массив:

  • var movieCount = 0
  • var songCount = 0
  • for item in library {
  • if item is Movie {
  • ++movieCount
  • } else if item is Song {
  • ++songCount
  • }
  • }
  • println("Media library contains \(movieCount) movies and \(songCount) songs")
  • // prints "Media library contains 2 movies and 3 songs"

Этот пример выполняет итерации через все элементы в library массив. На каждой передаче, for-in цикл устанавливает item постоянный к следующему MediaItem в массиве.

item is Movie возвраты true если ток MediaItem a Movie экземпляр и false если это не. Точно так же item is Song проверки, является ли элемент a Song экземпляр. В конце for-in цикл, значения movieCount и songCount содержите количество сколько MediaItem экземпляры были найдены каждого типа.

Downcasting

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

Поскольку downcasting может перестать работать, оператор броска типа приезжает в два различных форм. Условная форма, as?, возвращает дополнительное значение типа, к которому Вы пробуете к нисходящему. Принудительная форма, as!, делает попытку нисходящего, и сила - разворачивает результат как единственное составное действие.

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

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

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

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

  • for item in library {
  • if let movie = item as? Movie {
  • println("Movie: '\(movie.name)', dir. \(movie.director)")
  • } else if let song = item as? Song {
  • println("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 как a Movie. Поскольку item a MediaItem экземпляр, возможно, что это мог бы быть a Movie; одинаково, также возможно, что это мог бы быть a Song, или даже просто основа MediaItem. Из-за этой неопределенности, as? форма типа бросила возвраты оператора дополнительное значение при попытке к нисходящему к типу подкласса. Результат item as? Movie имеет тип Movie?, или “дополнительный Movie”.

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

“Попытайтесь получить доступ item как a Movie. Если это успешно, установите новую временную вызванную константу movie к значению, сохраненному в возвращенном дополнительном Movie.”

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

Преобразование типа для любого и AnyObject

Swift обеспечивает два специальных псевдонима типа для работы с неопределенными типами:

  • AnyObject может представлять экземпляр любого типа класса.

  • Any может представлять экземпляр любого типа вообще, включая функциональные типы.

AnyObject

При работе с Какао APIs распространено получить массив с типом [AnyObject], или “массив значений любого типа объекта”. Это вызвано тем, что Objective C не имеет явно типизированных массивов. Однако можно часто быть уверены в типе объектов, содержавшихся в таком массиве только от информации, которую Вы знаете о API, обеспечившем массив.

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

Пример ниже определяет массив типа [AnyObject] и заполняет этот массив с тремя экземплярами Movie класс:

  • let someObjects: [AnyObject] = [
  • Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
  • Movie(name: "Moon", director: "Duncan Jones"),
  • Movie(name: "Alien", director: "Ridley Scott")
  • ]

Поскольку этот массив, как известно, содержит только Movie экземпляры, Вы можете нисходящий и разворачивать непосредственно к обязательному Movie с принудительной версией типа бросает оператора (as!):

  • for object in someObjects {
  • let movie = object as! Movie
  • println("Movie: '\(movie.name)', dir. \(movie.director)")
  • }
  • // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
  • // Movie: 'Moon', dir. Duncan Jones
  • // Movie: 'Alien', dir. Ridley Scott

Для еще более короткой формы этого цикла, нисходящего someObjects выстройте к типу [Movie] вместо downcasting каждый элемент:

  • for movie in someObjects as! [Movie] {
  • println("Movie: '\(movie.name)', dir. \(movie.director)")
  • }
  • // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
  • // Movie: 'Moon', dir. Duncan Jones
  • // Movie: 'Alien', dir. Ridley Scott

Любой

Вот пример использования Any работать с соединением различных типов, включая функциональные типы и нетипы классов. Пример создает вызванный массив things, который может сохранить значения типа Any:

  • var things = [Any]()
  • things.append(0)
  • things.append(0.0)
  • things.append(42)
  • things.append(3.14159)
  • things.append("hello")
  • things.append((3.0, 5.0))
  • things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
  • things.append({ (name: String) -> String in "Hello, \(name)" })

things массив содержит два Int значения, два Double значения, a String значение, кортеж типа (Double, Double), «Охотники за привидениями» фильма и выражение закрытия, берущее a String оцените и возвращает другого String значение.

Можно использовать is и as операторы в a switch случаи оператора для обнаружения определенного типа константы или переменный, который, как известно, только имеет тип Any или AnyObject. Пример ниже выполняет итерации по элементам в things массив и запросы тип каждого элемента с a switch оператор. Несколько из switch случаи оператора обязывают свое соответствующее значение с константой указанного типа позволять его значению быть распечатанным:

  • for thing in things {
  • switch thing {
  • case 0 as Int:
  • println("zero as an Int")
  • case 0 as Double:
  • println("zero as a Double")
  • case let someInt as Int:
  • println("an integer value of \(someInt)")
  • case let someDouble as Double where someDouble > 0:
  • println("a positive double value of \(someDouble)")
  • case is Double:
  • println("some other double value that I don't want to print")
  • case let someString as String:
  • println("a string value of \"\(someString)\"")
  • case let (x, y) as (Double, Double):
  • println("an (x, y) point at \(x), \(y)")
  • case let movie as Movie:
  • println("a movie called '\(movie.name)', dir. \(movie.director)")
  • case let stringConverter as String -> String:
  • println(stringConverter("Michael"))
  • default:
  • println("something else")
  • }
  • }
  • // zero as an Int
  • // zero as a Double
  • // an integer value of 42
  • // a positive double value of 3.14159
  • // a string value of "hello"
  • // an (x, y) point at 3.0, 5.0
  • // a movie called 'Ghostbusters', dir. Ivan Reitman
  • // Hello, Michael