Swift - opcjonalne łączenie łańcuchowe

Proces odpytywania, wywoływania właściwości, indeksów i metod na opcji, która może mieć wartość „zero”, jest definiowana jako opcjonalne tworzenie łańcuchów. Opcjonalne tworzenie łańcuchów zwraca dwie wartości -

  • jeśli opcja zawiera „wartość”, wywołanie powiązanej z nią właściwości, metod i indeksów zwraca wartości

  • jeśli opcjonalne zawiera wartość „nil”, wszystkie związane z nim właściwości, metody i indeksy dolne zwracają nil

Ponieważ wiele zapytań do metod, właściwości i indeksów jest zgrupowanych razem, awaria jednego łańcucha wpłynie na cały łańcuch i spowoduje uzyskanie wartości „zero”.

Opcjonalne tworzenie łańcuchów jako alternatywa dla wymuszonego rozpakowywania

Opcjonalne tworzenie łańcucha jest określone po opcjonalnej wartości ze znakiem „?” do wywołania właściwości, metody lub indeksu dolnego, gdy opcjonalna wartość zwraca pewne wartości.

Opcjonalne łączenie „?” Dostęp do metod, właściwości i indeksów Opcjonalne tworzenie łańcuchów „!” wymusić rozpakowywanie
? jest umieszczany po opcjonalnej wartości wywołania właściwości, metody lub indeksu dolnego ! jest umieszczany po opcjonalnej wartości w celu wywołania właściwości, metody lub indeksu dolnego w celu wymuszenia rozpakowania wartości
Zawodzi z wdziękiem, gdy opcja jest „zero” Wymuszone rozpakowywanie wyzwala błąd czasu wykonywania, gdy opcja ma wartość „zero”

Program opcjonalnego łączenia łańcuchowego z „!”

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Powyższy program deklaruje „sondę wyborczą” jako nazwę klasy i zawiera „kandydata” jako funkcję członkostwa. Podklasa jest zadeklarowana jako „stanowisko ankietowe” i „nazwa” jako jej funkcja członkostwa, która jest inicjowana jako „poseł”. Wywołanie superklasy jest inicjowane przez utworzenie instancji „cand” z opcjonalnym „!”. Ponieważ wartości nie są zadeklarowane w swojej klasie bazowej, wartość „nil” jest przechowywana, co powoduje zwrócenie błędu krytycznego przez procedurę wymuszania rozpakowywania.

Program opcjonalnego łączenia łańcuchowego z „?”

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Candidate name cannot be retreived

Powyższy program deklaruje „sondę wyborczą” jako nazwę klasy i zawiera „kandydata” jako funkcję członkostwa. Podklasa jest zadeklarowana jako „stanowisko ankietowe” i „nazwa” jako jej funkcja członkostwa, która jest inicjowana jako „poseł”. Wywołanie superklasy jest inicjowane przez utworzenie instancji „cand” z opcjonalnym „?”. Ponieważ wartości nie są zadeklarowane w swojej klasie bazowej, wartość „nil” jest przechowywana i drukowana w konsoli przez blok obsługi else.

Definiowanie klas modeli dla opcjonalnych właściwości łączenia i uzyskiwania dostępu

Język Swift 4 zapewnia również koncepcję opcjonalnego łączenia łańcuchowego, aby zadeklarować więcej niż jedną podklasę jako klasy modelowe. Koncepcja ta będzie bardzo przydatna do definiowania złożonych modeli i uzyskiwania dostępu do właściwości, metod i pod-właściwości indeksów dolnych.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Rectangle Area is not specified

Wywoływanie metod poprzez opcjonalne łączenie łańcuchowe

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Area of circle is not specified

Funkcja circleprint () zadeklarowana w podklasie circle () jest wywoływana przez utworzenie instancji o nazwie „Circname”. Funkcja zwróci wartość, jeśli zawiera jakąś wartość, w przeciwnym razie zwróci jakiś komunikat drukowania zdefiniowany przez użytkownika, sprawdzając instrukcję „if circname.print? .Circleprint ()! = Nil”.

Dostęp do subskrypcji poprzez opcjonalne tworzenie łańcuchów

Opcjonalne tworzenie łańcucha służy do ustawiania i pobierania wartości indeksu dolnego w celu sprawdzenia, czy wywołanie tego indeksu zwraca wartość. '?' jest umieszczany przed nawiasami klamrowymi, aby uzyskać dostęp do opcjonalnej wartości w danym indeksie dolnym.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Radius is not specified.

W powyższym programie nie określono wartości instancji funkcji członkostwa „radiusName”. Dlatego wywołanie funkcji zwróci tylko inną część, podczas gdy aby zwrócić wartości, musimy zdefiniować wartości dla konkretnej funkcji przynależności.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Radius is measured in Units.

W powyższym programie określono wartości instancji funkcji członkostwa „radiusName”. Dlatego wywołanie funkcji w programie będzie teraz zwracać wartości.

Dostęp do indeksów dolnych typu opcjonalnego

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

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

Dostęp do opcjonalnych wartości dla indeksów dolnych można uzyskać, odwołując się do ich wartości w indeksie dolnym. Dostęp do niego można uzyskać jako indeks dolny [0], indeks dolny [1] itd. Domyślne wartości indeksu dolnego dla „promienia” są najpierw przypisywane jako [35, 45, 78, 101] i dla „Circle” [90, 45, 56]] . Następnie wartości indeksu dolnego są zmieniane jako Promień [0] na 78 i Okrąg [1] na 45.

Łączenie wielu poziomów łańcuchów

Wiele podklas może być również połączonych z ich metodami, właściwościami i indeksami superklas przez opcjonalne tworzenie łańcuchów.

Możliwość łączenia wielu opcjonalnych łańcuchów -

Jeśli pobieranie typu nie jest opcjonalne, opcjonalne tworzenie łańcucha zwróci opcjonalną wartość. Na przykład, jeśli String przez opcjonalne łańcuchowanie zwróci String? Wartość

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Radius is not specified.

W powyższym programie nie określono wartości instancji funkcji członkostwa „radiusName”. W związku z tym wywołanie funkcji zwróci tylko inną część, podczas gdy aby zwrócić wartości, musimy zdefiniować wartości dla określonej funkcji przynależności.

Jeśli typ pobierania jest już opcjonalny, opcjonalne tworzenie łańcucha również zwróci wartość opcjonalną. Na przykład, jeśli String? Czy jest dostępny przez opcjonalne łańcuchowanie, zwróci String? Wartość..

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Radius is measured in Units.

W powyższym programie określono wartości instancji funkcji członkostwa „radiusName”. W związku z tym wywołanie funkcji w programie zwróci teraz wartości.

Tworzenie łańcuchów metod z opcjonalnymi wartościami zwracanymi

Opcjonalne tworzenie łańcuchów jest również używane do uzyskiwania dostępu do metod zdefiniowanych podklas.

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

Gdy uruchomimy powyższy program za pomocą placu zabaw, otrzymamy następujący wynik -

Area of circle is not specified