Swift - Chaining เสริม

กระบวนการสอบถามเรียกคุณสมบัติตัวห้อยและเมธอดบนทางเลือกที่อาจเป็น 'nil' ถูกกำหนดให้เป็นโซ่ทางเลือก การผูกมัดทางเลือกส่งคืนค่าสองค่า -

  • หากทางเลือกมี 'ค่า' การเรียกคุณสมบัติที่เกี่ยวข้องวิธีการและตัวห้อยจะส่งกลับค่า

  • หากทางเลือกมีค่า 'nil' คุณสมบัติที่เกี่ยวข้องทั้งหมดวิธีการและตัวห้อยจะส่งกลับค่า nil

เนื่องจากการสืบค้นหลายวิธีไปจนถึงวิธีการคุณสมบัติและตัวห้อยจึงถูกจัดกลุ่มเข้าด้วยกันความล้มเหลวในห่วงโซ่เดียวจะส่งผลต่อห่วงโซ่ทั้งหมดและส่งผลให้ค่า 'ศูนย์'

การเชื่อมโยงทางเลือกเป็นทางเลือกในการยกเลิกการห่อแบบบังคับ

การต่อโซ่ทางเลือกถูกระบุไว้หลังค่าทางเลือกด้วย '? เพื่อเรียกคุณสมบัติเมธอดหรือตัวห้อยเมื่อค่าทางเลือกส่งกลับค่าบางค่า

ตัวเลือก Chaining '?' เข้าถึงเมธอดคุณสมบัติและตัวห้อย เพื่อบังคับให้ Unwrapping
เหรอ? ถูกวางไว้หลังค่าทางเลือกเพื่อเรียกคุณสมบัติเมธอดหรือตัวห้อย ! ถูกวางไว้หลังค่าทางเลือกในการเรียกคุณสมบัติวิธีการหรือตัวห้อยเพื่อบังคับให้คลายค่า
ล้มเหลวอย่างสง่างามเมื่อตัวเลือกคือ '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' จึงถูกเก็บไว้ดังนั้นจึงส่งคืนข้อผิดพลาดร้ายแรงโดยขั้นตอนการคลายแรง

โปรแกรมสำหรับการเชื่อมโยงทางเลือกด้วย "?"

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' ของคลาสพื้นฐานจะถูกจัดเก็บและพิมพ์ในคอนโซลโดยบล็อกตัวจัดการอื่น

การกำหนดคลาสโมเดลสำหรับการเชื่อมโยงและการเข้าถึงคุณสมบัติเสริม

ภาษา Swift 4 ยังให้แนวคิดของการเชื่อมโยงทางเลือกเพื่อประกาศคลาสย่อยมากกว่าหนึ่งคลาสเป็นคลาสโมเดล แนวคิดนี้จะมีประโยชน์มากในการกำหนดแบบจำลองที่ซับซ้อนและเพื่อเข้าถึงคุณสมบัติวิธีการและคุณสมบัติย่อยของตัวห้อย

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

วิธีการโทรผ่านโซ่เสริม

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'

การเข้าถึง Subscripts ผ่านทางเลือก Chaining

การเชื่อมโยงทางเลือกใช้เพื่อตั้งค่าและดึงค่าตัวห้อยเพื่อตรวจสอบว่าการเรียกไปยังตัวห้อยนั้นส่งคืนค่าหรือไม่ '?' วางไว้ก่อนวงเล็บปีกกาตัวห้อยเพื่อเข้าถึงค่าทางเลือกบนตัวห้อยเฉพาะ

โปรแกรม 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.")
}

เมื่อเรารันโปรแกรมข้างต้นโดยใช้สนามเด็กเล่นเราจะได้ผลลัพธ์ดังนี้ -

Radius is not specified.

ในโปรแกรมข้างต้นไม่ได้ระบุค่าอินสแตนซ์สำหรับฟังก์ชันการเป็นสมาชิก 'radiusName' ดังนั้นการเรียกโปรแกรมไปยังฟังก์ชันจะส่งคืนเฉพาะส่วนอื่นในขณะที่การส่งคืนค่าเราต้องกำหนดค่าสำหรับฟังก์ชันการเป็นสมาชิกโดยเฉพาะ

โปรแกรม 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.")
}

เมื่อเรารันโปรแกรมข้างต้นโดยใช้สนามเด็กเล่นเราจะได้ผลลัพธ์ดังนี้ -

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)

ค่าที่เป็นทางเลือกสำหรับ subscripts สามารถเข้าถึงได้โดยอ้างถึงค่า subscript สามารถเข้าถึงได้เป็นตัวห้อย [0] ตัวห้อย [1] ฯลฯ ค่าตัวห้อยเริ่มต้นสำหรับ "รัศมี" จะถูกกำหนดเป็นครั้งแรกเป็น [35, 45, 78, 101] และสำหรับ "วงกลม" [90, 45, 56]] . จากนั้นค่าตัวห้อยจะเปลี่ยนเป็นรัศมี [0] เป็น 78 และวงกลม [1] เป็น 45

การเชื่อมโยงหลายระดับของ Chaining

นอกจากนี้ยังสามารถเชื่อมโยงคลาสย่อยหลายคลาสด้วยเมธอดคุณสมบัติและตัวห้อยระดับซุปเปอร์โดยการผูกมัดที่เป็นทางเลือก

สามารถเชื่อมโยงหลาย ๆ ตัวเลือกได้ -

หากไม่จำเป็นต้องใช้การดึงชนิดการเชื่อมโยงทางเลือกจะส่งคืนค่าที่เป็นทางเลือก ตัวอย่างเช่นถ้า String ผ่านทางเลือก Chaining มันจะส่งคืน String? มูลค่า

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? เข้าถึงผ่านการผูกมัดที่เป็นทางเลือกมันจะส่งคืน String หรือไม่ ค่า ..

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("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