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