Swift - Optionale Verkettung

Das Abfragen, Aufrufen von Eigenschaften, Indizes und Methoden für ein optionales Element, das möglicherweise 'nil' ist, wird als optionale Verkettung definiert. Optionale Verkettung gibt zwei Werte zurück -

  • Wenn das optionale Element einen 'Wert' enthält, werden beim Aufrufen der zugehörigen Eigenschaft, Methoden und Indizes Werte zurückgegeben

  • Wenn das optionale Element den Wert 'nil' enthält, geben alle zugehörigen Eigenschaften, Methoden und Indizes nil zurück

Da mehrere Abfragen zu Methoden, Eigenschaften und Indizes zusammengefasst sind, wirkt sich ein Fehler in einer Kette auf die gesamte Kette aus und führt zu einem Nullwert.

Optionale Verkettung als Alternative zum erzwungenen Auspacken

Die optionale Verkettung wird nach dem optionalen Wert mit '?' um eine Eigenschaft, Methode oder einen Index aufzurufen, wenn der optionale Wert einige Werte zurückgibt.

Optionale Verkettung '?' Zugriff auf Methoden, Eigenschaften und IndizesOptional Chaining '!' Auspacken erzwingen
? wird nach dem optionalen Wert zum Aufrufen von Eigenschaft, Methode oder Index platziert ! wird nach dem optionalen Wert platziert, um die Eigenschaft, Methode oder den Index aufzurufen und das Entpacken des Werts zu erzwingen
Schlägt ordnungsgemäß fehl, wenn das optionale Element "Null" ist. Das erzwungene Entpacken löst einen Laufzeitfehler aus, wenn das optionale Element 'nil' ist.

Programm zur optionalen Verkettung mit '!'

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

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

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

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

Das obige Programm deklariert "Wahlumfrage" als Klassennamen und enthält "Kandidat" als Mitgliedschaftsfunktion. Die Unterklasse wird als 'Wahlkabine' und 'Name' als Zugehörigkeitsfunktion deklariert, die als 'MP' initialisiert wird. Der Aufruf der Superklasse wird durch Erstellen einer Instanz 'cand' mit optionalem '!' Initialisiert. Da die Werte nicht in ihrer Basisklasse deklariert sind, wird der Wert 'nil' gespeichert, wodurch ein schwerwiegender Fehler durch das Erzwingen des Entpackens zurückgegeben wird.

Programm für optionale Verkettung mit '?'

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")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Candidate name cannot be retreived

Das obige Programm deklariert "Wahlumfrage" als Klassennamen und enthält "Kandidat" als Mitgliedschaftsfunktion. Die Unterklasse wird als 'Wahlkabine' und 'Name' als Zugehörigkeitsfunktion deklariert, die als 'MP' initialisiert wird. Der Aufruf der Superklasse wird durch Erstellen einer Instanz 'cand' mit optionalem '?' Initialisiert. Da die Werte in ihrer Basisklasse nicht deklariert sind, wird der Wert 'nil' vom else-Handlerblock in der Konsole gespeichert und gedruckt.

Definieren von Modellklassen für optionale Verkettung und Zugriff auf Eigenschaften

Die Sprache Swift 4 bietet auch das Konzept der optionalen Verkettung, um mehr als eine Unterklasse als Modellklassen zu deklarieren. Dieses Konzept ist sehr nützlich, um komplexe Modelle zu definieren und auf die Eigenschaften von Eigenschaften, Methoden und Indizes zuzugreifen.

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")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Rectangle Area is not specified

Aufrufmethoden durch optionale Verkettung

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")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Area of circle is not specified

Die in der Unterklasse circle () deklarierte Funktion circleprint () wird durch Erstellen einer Instanz mit dem Namen 'circname' aufgerufen. Die Funktion gibt einen Wert zurück, wenn sie einen Wert enthält, andernfalls gibt sie eine benutzerdefinierte Drucknachricht zurück, indem sie die Anweisung 'if circname.print? .Circleprint ()! = Nil' überprüft.

Zugriff auf Indizes über optionale Verkettung

Die optionale Verkettung wird verwendet, um einen Indexwert festzulegen und abzurufen, um zu überprüfen, ob der Aufruf dieses Index einen Wert zurückgibt. '?' wird vor die tiefgestellten Klammern gesetzt, um auf den optionalen Wert des jeweiligen Index zuzugreifen.

Programm 1

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.")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Radius is not specified.

Im obigen Programm sind die Instanzwerte für die Zugehörigkeitsfunktion 'radiusName' nicht angegeben. Daher gibt der Programmaufruf der Funktion nur einen anderen Teil zurück, während wir die Werte für die jeweilige Zugehörigkeitsfunktion definieren müssen, um die Werte zurückzugeben.

Programm 2

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.")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Radius is measured in Units.

Im obigen Programm werden die Instanzwerte für die Zugehörigkeitsfunktion 'radiusName' angegeben. Daher gibt der Programmaufruf der Funktion jetzt Werte zurück.

Zugriff auf Indizes vom optionalen Typ

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])

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

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

Auf die optionalen Werte für Indizes kann zugegriffen werden, indem auf deren Indexwerte verwiesen wird. Es kann als Index [0], Index [1] usw. zugegriffen werden. Die Standard-Indexwerte für 'Radius' werden zuerst als [35, 45, 78, 101] und für 'Kreis' [90, 45, 56] zugewiesen.] . Dann werden die tiefgestellten Werte als Radius [0] auf 78 und Kreis [1] auf 45 geändert.

Verknüpfung mehrerer Verkettungsebenen

Durch optionale Verkettung können auch mehrere Unterklassen mit ihren Methoden, Eigenschaften und Indizes für Superklassen verknüpft werden.

Mehrfachverkettung von optional kann verknüpft werden -

Wenn das Abrufen des Typs nicht optional ist, gibt die optionale Verkettung einen optionalen Wert zurück. Wenn beispielsweise String durch optionale Verkettung String zurückgibt? Wert

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.")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Radius is not specified.

Im obigen Programm sind die Instanzwerte für die Zugehörigkeitsfunktion 'radiusName' nicht angegeben. Daher gibt der Programmaufruf der Funktion nur einen anderen Teil zurück, während wir zum Zurückgeben der Werte die Werte für die bestimmte Zugehörigkeitsfunktion definieren müssen.

Wenn der Abruftyp bereits optional ist, gibt die optionale Verkettung auch einen optionalen Wert zurück. Zum Beispiel wenn String? Wird über eine optionale Verkettung zugegriffen, wird ein String zurückgegeben? Wert..

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.")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Radius is measured in Units.

Im obigen Programm werden die Instanzwerte für die Zugehörigkeitsfunktion 'radiusName' angegeben. Daher gibt der Programmaufruf der Funktion jetzt Werte zurück.

Verkettung von Methoden mit optionalen Rückgabewerten

Die optionale Verkettung wird auch verwendet, um auf unterklassendefinierte Methoden zuzugreifen.

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")
}

Wenn wir das obige Programm auf einem Spielplatz ausführen, erhalten wir das folgende Ergebnis:

Area of circle is not specified