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

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

Разработчик

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

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

Дополнительное объединение в цепочку

Дополнительное объединение в цепочку является процессом для того, чтобы запросить и вызвать свойства, методы, и преобразовывает в нижний индекс на дополнительном, которое могло бы в настоящее время быть nil. Если дополнительное содержит значение, свойство, метод, или нижний вызов успешно выполняется; если дополнительное nil, свойство, метод или нижний индекс вызывают возвраты nil. Многократные запросы могут быть объединены в цепочку вместе, и вся цепочка перестала работать корректно, если какая-либо ссылка в цепочке nil.

Дополнительное объединение в цепочку как альтернатива принудительному разворачиванию

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

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

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

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

Во-первых, два класса вызывают Person и Residence определяются:

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

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

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

  • let john = Person()

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

  • let roomCount = john.residence!.numberOfRooms
  • // this triggers a runtime error

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

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

  • if let roomCount = john.residence?.numberOfRooms {
  • println("John's residence has \(roomCount) room(s).")
  • } else {
  • println("Unable to retrieve the number of rooms.")
  • }
  • // prints "Unable to retrieve the number of rooms."

Это говорит Свифту «цепочке» на дополнительном residence свойство и получать значение numberOfRooms если residence существует.

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

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

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

  • john.residence = Residence()

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

  • if let roomCount = john.residence?.numberOfRooms {
  • println("John's residence has \(roomCount) room(s).")
  • } else {
  • println("Unable to retrieve the number of rooms.")
  • }
  • // prints "John's residence has 1 room(s)."

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

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

Фрагменты кода ниже определяют четыре класса модели для использования в нескольких последующих примерах, включая примеры многоуровневого дополнительного объединения в цепочку. Эти классы подробно останавливаются Person и Residence смоделируйте сверху путем добавления a Room и Address класс, со связанными свойствами, методами и нижними индексами.

Person класс определяется таким же образом как прежде:

  • class Person {
  • var residence: Residence?
  • }

Residence класс более сложен, чем прежде. На сей раз, Residence класс определяет переменное вызванное свойство rooms, который инициализируется с пустым массивом типа [Room]:

  • class Residence {
  • var rooms = [Room]()
  • var numberOfRooms: Int {
  • return rooms.count
  • }
  • subscript(i: Int) -> Room {
  • get {
  • return rooms[i]
  • }
  • set {
  • rooms[i] = newValue
  • }
  • }
  • func printNumberOfRooms() {
  • println("The number of rooms is \(numberOfRooms)")
  • }
  • var address: Address?
  • }

Поскольку эта версия Residence хранит массив Room экземпляры, numberOfRooms свойство реализовано как вычисленное свойство, не сохраненное свойство. Вычисленный numberOfRooms свойство просто возвращает значение count свойство от rooms массив.

Как ярлык на доступ к rooms массив, эта версия Residence обеспечивает нижний индекс чтения-записи, обеспечивающий доступ к комнате в требуемом индексе в rooms массив.

Эта версия Residence также обеспечивает вызванный метод printNumberOfRooms, который просто распечатывает число комнат в местонахождении.

Наконец, Residence определяет дополнительное вызванное свойство address, с типом Address?. Address тип класса для этого свойства определяется ниже.

Room класс, используемый для rooms массив является простым классом с одним вызванным свойством name, и инициализатор для установки того свойства в подходящее имя помещения:

  • class Room {
  • let name: String
  • init(name: String) { self.name = name }
  • }

Заключительный класс в этой модели вызывают Address. Этот класс имеет три дополнительных свойства типа String?. Первые два свойства, buildingName и buildingNumber, альтернативные способы идентифицировать определенное здание как часть адреса. Третье свойство, street, используется для именования улицы для того адреса:

  • class Address {
  • var buildingName: String?
  • var buildingNumber: String?
  • var street: String?
  • func buildingIdentifier() -> String? {
  • if buildingName != nil {
  • return buildingName
  • } else if buildingNumber != nil {
  • return buildingNumber
  • } else {
  • return nil
  • }
  • }
  • }

Address класс также обеспечивает вызванный метод buildingIdentifier, который имеет тип возврата String?. Этот метод проверяет buildingName и buildingNumber свойства и возвраты buildingName если это имеет значение, или buildingNumber если это имеет значение, или nil если никакое свойство не имеет значение.

Доступ к свойствам посредством дополнительного объединения в цепочку

Как продемонстрировано в Дополнительном Объединении в цепочку как Альтернатива Принудительному Разворачиванию, можно использовать дополнительное объединение в цепочку, чтобы получить доступ к свойству на дополнительном значении и проверить, успешен ли тот доступ свойства.

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

  • let john = Person()
  • if let roomCount = john.residence?.numberOfRooms {
  • println("John's residence has \(roomCount) room(s).")
  • } else {
  • println("Unable to retrieve the number of rooms.")
  • }
  • // prints "Unable to retrieve the number of rooms."

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

Можно также попытаться установить значение свойства посредством дополнительного объединения в цепочку:

  • let someAddress = Address()
  • someAddress.buildingNumber = "29"
  • someAddress.street = "Acacia Road"
  • john.residence?.address = someAddress

В этом примере, попытка установить address свойство john.residence перестанет работать, потому что john.residence в настоящее время nil.

Вызывающие методы посредством дополнительного объединения в цепочку

Можно использовать дополнительное объединение в цепочку, чтобы вызвать метод на дополнительном значении и проверить, успешен ли тот вызов метода. Даже если тот метод не определяет возвращаемое значение, можно сделать это.

printNumberOfRooms() метод на Residence класс распечатывает текущую стоимость numberOfRooms. Вот то, как смотрит метод:

  • func printNumberOfRooms() {
  • println("The number of rooms is \(numberOfRooms)")
  • }

Этот метод не указывает тип возврата. Однако функции и методы без типа возврата имеют неявный тип возврата Void, как описано в Функциях Без Возвращаемых значений. Это означает, что они возвращают значение (), или пустой кортеж.

При вызове этого метода на дополнительном значении с дополнительным объединением в цепочку тип возврата метода будет Void?, нет Void, потому что возвращаемые значения всегда имеют дополнительный тип, когда вызвано посредством дополнительного объединения в цепочку. Это позволяет Вам использовать if оператор, чтобы проверить, было ли возможно вызвать printNumberOfRooms() метод, даже при том, что метод самостоятельно не определяет возвращаемое значение. Сравните возвращаемое значение от printNumberOfRooms вызовите против nil видеть, был ли вызов метода успешен:

  • if john.residence?.printNumberOfRooms() != nil {
  • println("It was possible to print the number of rooms.")
  • } else {
  • println("It was not possible to print the number of rooms.")
  • }
  • // prints "It was not possible to print the number of rooms."

При попытке установить свойство посредством дополнительного объединения в цепочку, то же является истиной. Пример выше в Доступе к Свойствам Посредством Дополнительного Объединения в цепочку пытается установить address значение для john.residence, даже при том, что residence свойство nil. Любая попытка установить свойство посредством дополнительного объединения в цепочку возвращает значение типа Void?, который позволяет Вам выдержать сравнение с nil видеть, было ли свойство установлено успешно:

  • if (john.residence?.address = someAddress) != nil {
  • println("It was possible to set the address.")
  • } else {
  • println("It was not possible to set the address.")
  • }
  • // prints "It was not possible to set the address."

Доступ к нижним индексам посредством дополнительного объединения в цепочку

Можно использовать дополнительное объединение в цепочку, чтобы попытаться получить и установить значение от нижнего индекса на дополнительном значении и проверить, успешен ли тот нижний вызов.

Пример ниже пытается получить имя первой комнаты в rooms массив john.residence свойство с помощью нижнего индекса, определенного на Residence класс. Поскольку john.residence в настоящее время nil, нижние сбои вызова:

  • if let firstRoomName = john.residence?[0].name {
  • println("The first room name is \(firstRoomName).")
  • } else {
  • println("Unable to retrieve the first room name.")
  • }
  • // prints "Unable to retrieve the first room name."

Дополнительный вопросительный знак объединения в цепочку в этом нижнем вызове сразу помещается после john.residence, перед нижними скобками, потому что john.residence дополнительное значение, на котором пробуется дополнительное объединение в цепочку.

Точно так же можно попытаться установить новое значение через нижний индекс с дополнительным объединением в цепочку:

  • john.residence?[0] = Room(name: "Bathroom")

Эта попытка установки нижнего индекса также перестала работать, потому что residence в настоящее время nil.

Если Вы создаете и присваиваете фактическое Residence экземпляр к john.residence, с один или больше Room экземпляры в rooms массив, можно использовать Residence преобразуйте в нижний индекс для доступа к фактическим элементам в rooms массив посредством дополнительного объединения в цепочку:

  • let johnsHouse = Residence()
  • johnsHouse.rooms.append(Room(name: "Living Room"))
  • johnsHouse.rooms.append(Room(name: "Kitchen"))
  • john.residence = johnsHouse
  • if let firstRoomName = john.residence?[0].name {
  • println("The first room name is \(firstRoomName).")
  • } else {
  • println("Unable to retrieve the first room name.")
  • }
  • // prints "The first room name is Living Room."

Доступ к нижним индексам дополнительного типа

Если нижний индекс возвращает значение дополнительного типа — такого как ключевой нижний индекс Swift Dictionary введите — помещают вопросительный знак после закрывающей скобки нижнего индекса к цепочке на ее дополнительном возвращаемом значении:

  • var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
  • testScores["Dave"]?[0] = 91
  • testScores["Bev"]?[0]++
  • testScores["Brian"]?[0] = 72
  • // the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81]

Пример выше определяет вызванный словарь testScores, который содержит две пары ключ/значение та карта a String ключ к массиву Int значения. Пример использует дополнительное объединение в цепочку для установки первого элемента в "Dave" массив к 91; постепенно увеличить первый элемент в "Bev" массив 1; и попытаться установить первый элемент в массиве для ключа "Brian". Первые два вызова успешно выполняются, потому что testScores словарь содержит ключи для "Dave" и "Bev". Третьи сбои вызова, потому что testScores словарь не содержит ключ для "Brian".

Соединение многократных уровней объединения в цепочку

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

Помещать его иначе:

  • Если тип, который Вы пытаетесь получить, не будет дополнительным, то это станет дополнительным из-за дополнительного объединения в цепочку.

  • Если тип, который Вы пытаетесь получить, будет уже дополнительным, то это не станет более дополнительным из-за объединения в цепочку.

Поэтому:

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

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

Пример ниже пытается получить доступ street свойство address свойство residence свойство john. Существует два уровня дополнительного объединения в цепочку в использовании здесь к цепочке через residence и address свойства, оба из которых имеют дополнительный тип:

  • if let johnsStreet = john.residence?.address?.street {
  • println("John's street name is \(johnsStreet).")
  • } else {
  • println("Unable to retrieve the address.")
  • }
  • // prints "Unable to retrieve the address."

Значение john.residence в настоящее время содержит допустимое Residence экземпляр. Однако значение john.residence.address в настоящее время nil. Из-за этого, вызова к john.residence?.address?.street сбои.

Обратите внимание на то, что в примере выше, Вы пытаетесь получить значение street свойство. Тип этого свойства String?. Возвращаемое значение john.residence?.address?.street поэтому также String?, даже при том, что два уровня дополнительного объединения в цепочку применяются в дополнение к базовому дополнительному типу свойства.

Если Вы устанавливаете фактическое Address экземпляр как значение для john.residence.address, и набор фактическое значение для адреса street свойство, можно получить доступ к значению street свойство посредством многоуровневого дополнительного объединения в цепочку:

  • let johnsAddress = Address()
  • johnsAddress.buildingName = "The Larches"
  • johnsAddress.street = "Laurel Street"
  • john.residence!.address = johnsAddress
  • if let johnsStreet = john.residence?.address?.street {
  • println("John's street name is \(johnsStreet).")
  • } else {
  • println("Unable to retrieve the address.")
  • }
  • // prints "John's street name is Laurel Street."

Отметьте использование восклицательного знака во время присвоения экземпляра адреса к john.residence.address. john.residence свойство имеет дополнительный тип, и таким образом, необходимо развернуть его фактическое значение с восклицательным знаком прежде, чем получить доступ к местонахождению address свойство.

Объединение в цепочку на методах с дополнительными возвращаемыми значениями

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

Пример ниже вызывает Address класс buildingIdentifier() метод посредством дополнительного объединения в цепочку. Этот метод возвращает значение типа String?. Как описано выше, окончательный тип возврата этого вызова метода после того, как дополнительное объединение в цепочку также String?:

  • if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
  • println("John's building identifier is \(buildingIdentifier).")
  • }
  • // prints "John's building identifier is The Larches."

Если Вы хотите выполнить далее дополнительное объединение в цепочку на возвращаемом значении этого метода, поместить дополнительный вопросительный знак объединения в цепочку после круглых скобок метода:

  • if let beginsWithThe =
  • john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
  • if beginsWithThe {
  • println("John's building identifier begins with \"The\".")
  • } else {
  • println("John's building identifier does not begin with \"The\".")
  • }
  • }
  • // prints "John's building identifier begins with "The"."