Учебники

Swift — опциональная цепочка

Процесс запроса, вызова свойств, подписок и методов для необязательного параметра, который может иметь значение «ноль», определяется как необязательное сцепление. Необязательная цепочка возвращает два значения —

  • если необязательный параметр содержит значение, то при вызове связанного с ним свойства методы и индексы возвращают значения

  • если необязательный параметр содержит значение ‘nil’, все связанные с ним свойства, методы и индексы возвращают nil

если необязательный параметр содержит значение, то при вызове связанного с ним свойства методы и индексы возвращают значения

если необязательный параметр содержит значение ‘nil’, все связанные с ним свойства, методы и индексы возвращают nil

Поскольку несколько запросов к методам, свойствам и индексам сгруппированы вместе, отказ одной цепочки повлияет на всю цепочку и приведет к значению ‘nil’.

Необязательное создание цепочки как альтернатива принудительной распаковке

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

Необязательная цепочка ‘?’ Доступ к методам, свойствам и подпискам. Опциональная цепочка ‘!’ заставить развернуть
? помещается после необязательного значения для вызова свойства, метода или индекса ! помещается после необязательного значения для вызова свойства, метода или индекса, чтобы принудительно развернуть значение
Сбои изящно, когда необязательный ‘ноль’ Принудительная распаковка вызывает ошибку во время выполнения, когда необязательный параметр ‘nil’

Программа для опциональной цепочки с ‘!’

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

let cand = ElectionPoll()
let candname = cand.candidate!.name

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

fatal error: unexpectedly found nil while unwrapping an Optional value
0 Swift 4 0x0000000103410b68
llvm::sys::PrintStackTrace(__sFILE*) + 40
1 Swift 4 0x0000000103411054 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26
3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939
4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636
5 Swift 4 0x0000000102a85c39
llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329
6 Swift 4 0x0000000102d320b3
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::__1::vector<std::__1::basic_string, std::__1::allocator >,
std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<std::__1::basic_string,
std::__1::allocator >, std::__1::allocator<std::__1::basic_string,
std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions
const&) + 1066
8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef,
char const*, void*) + 5275
9 Swift 4 0x0000000102754a6d main + 1677
10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1
11 libdyld.dylib 0x000000000000000c start + 1950751300
Stack dump:
0. Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 -
target-cpu core2 -sdk
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX10.10.sdk -module-name main
/bin/sh: line 47: 15672 Done cat <<'SWIFT 4'
import Foundation
</std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std::
__1::basic_string

Вышеуказанная программа объявляет «опрос выборов» в качестве имени класса и содержит «кандидат» в качестве функции членства. Подкласс объявляется как «опросная кабина», а «имя» — как функция членства, которая инициализируется как «MP». Вызов суперкласса инициализируется созданием экземпляра ‘Cand’ с необязательным ‘!’. Поскольку значения не объявлены в его базовом классе, значение ‘nil’ сохраняется, возвращая фатальную ошибку в процедуре принудительного развертывания.

Программа для необязательного связывания с ‘?’

Live Demo

class ElectionPoll {
   var candidate: Pollbooth?
}

class Pollbooth {
   var name = "MP"
}
let cand = ElectionPoll()

if let candname = cand.candidate?.name {
   print("Candidate name is \(candname)")
} else {
   print("Candidate name cannot be retreived")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Candidate name cannot be retreived

Программа выше объявляет «опрос выборов» в качестве имени класса и содержит «кандидат» в качестве функции членства. Подкласс объявляется как «опросная кабина», а «имя» — как функция членства, которая инициализируется как «MP». Вызов суперкласса инициализируется созданием экземпляра ‘Cand’ с необязательным ‘?’. Поскольку значения не объявлены в его базовом классе, значение ‘nil’ сохраняется и печатается в консоли блоком обработки else.

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

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

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var street: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let rectname = rectangle()
if let rectarea = rectname.print?.cprint {
   print("Area of rectangle is \(rectarea)")
} else {
   print("Rectangle Area is not specified")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Rectangle Area is not specified

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

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }

   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Area of circle is not specified

Функция circleprint (), объявленная внутри подкласса circle (), вызывается путем создания экземпляра с именем ‘circname’. Функция вернет значение, если оно содержит какое-либо значение, в противном случае она вернет определенное пользователем сообщение для печати, проверив оператор «if circname.print? .Circleprint ()! = Nil».

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

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

Программа 1

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname =  radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Radius is not specified.

В приведенной выше программе значения экземпляра для функции членства radiusName не указаны. Следовательно, программный вызов функции вернет только другую часть, тогда как для возврата значений мы должны определить значения для конкретной функции принадлежности.

Программа 2

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Radius is measured in Units.

В вышеприведенной программе указаны значения экземпляра для функции членства radiusName. Следовательно, программный вызов функции теперь будет возвращать значения.

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

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }

   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")

let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]]
area["Radius"]?[1] = 78
area["Circle"]?[1]--

print(area["Radius"]?[0])
print(area["Radius"]?[1])
print(area["Radius"]?[2])
print(area["Radius"]?[3])

print(area["Circle"]?[0])
print(area["Circle"]?[1])
print(area["Circle"]?[2])

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)

Доступ к дополнительным значениям для подписок можно получить, сославшись на их значения. Доступ к нему можно получить как индекс [0], индекс [1] и т. Д. Значения индекса по умолчанию для «радиуса» сначала назначаются как [35, 45, 78, 101] и для «круга» [90, 45, 56]] , Затем значения нижнего индекса изменяются как Радиус [0] на 78 и Круг [1] на 45.

Связывание нескольких уровней цепочки

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

Несколько цепочек необязательных могут быть связаны —

Если тип извлечения не является необязательным, необязательное сцепление вернет необязательное значение. Например, если String через необязательную цепочку вернет String? Значение

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Radius is not specified.

В приведенной выше программе значения экземпляра для функции членства radiusName не указаны. Следовательно, программный вызов функции вернет только другую часть, тогда как для возврата значений мы должны определить значения для конкретной функции принадлежности.

Если тип получения уже является необязательным, то необязательное сцепление также возвратит необязательное значение. Например, если строка? Доступ через необязательную цепочку вернет String? Значение..

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —

Radius is measured in Units.

В вышеприведенной программе указаны значения экземпляра для функции членства radiusName. Следовательно, программный вызов функции теперь будет возвращать значения.

Цепочка для методов с необязательными возвращаемыми значениями

Необязательное сцепление также используется для доступа к определенным методам подклассов.

Live Demo

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Когда мы запускаем вышеуказанную программу, используя площадку, мы получаем следующий результат —