
- Swift 教程
- Swift - 首頁
- Swift - 概述
- Swift - 環境
- Swift - 基本語法
- Swift - 變數
- Swift - 常量
- Swift - 字面量
- Swift - 註釋
- Swift 運算子
- Swift - 運算子
- Swift - 算術運算子
- Swift - 比較運算子
- Swift - 邏輯運算子
- Swift - 賦值運算子
- Swift - 位運算子
- Swift - 其他運算子
- Swift 高階運算子
- Swift - 運算子過載
- Swift - 算術溢位運算子
- Swift - 恆等運算子
- Swift - 範圍運算子
- Swift 資料型別
- Swift - 資料型別
- Swift - 整數
- Swift - 浮點數
- Swift - Double
- Swift - 布林值
- Swift - 字串
- Swift - 字元
- Swift - 類型別名
- Swift - 可選值
- Swift - 元組
- Swift - 斷言和前提條件
- Swift 控制流
- Swift - 決策
- Swift - if 語句
- Swift - if...else if...else 語句
- Swift - if-else 語句
- Swift - 巢狀 if 語句
- Swift - switch 語句
- Swift - 迴圈
- Swift - for in 迴圈
- Swift - while 迴圈
- Swift - repeat...while 迴圈
- Swift - continue 語句
- Swift - break 語句
- Swift - fallthrough 語句
- Swift 集合
- Swift - 陣列
- Swift - 集合
- Swift - 字典
- Swift 函式
- Swift - 函式
- Swift - 巢狀函式
- Swift - 函式過載
- Swift - 遞迴
- Swift - 高階函式
- Swift 閉包
- Swift - 閉包
- Swift - 轉義和非轉義閉包
- Swift - 自動閉包
- Swift 面向物件程式設計
- Swift - 列舉
- Swift - 結構體
- Swift - 類
- Swift - 屬性
- Swift - 方法
- Swift - 下標
- Swift - 繼承
- Swift - 重寫
- Swift - 初始化
- Swift - 析構
- Swift 高階特性
- Swift - ARC 概述
- Swift - 可選鏈
- Swift - 錯誤處理
- Swift - 併發
- Swift - 型別轉換
- Swift - 巢狀型別
- Swift - 擴充套件
- Swift - 協議
- Swift - 泛型
- Swift - 訪問控制
- Swift - 函式與方法
- Swift - SwiftyJSON
- Swift - 單例類
- Swift 隨機數
- Swift 不透明型別和裝箱型別
- Swift 有用資源
- Swift - 線上編譯
- Swift - 快速指南
- Swift - 有用資源
- Swift - 討論
Swift - 可選鏈
可選鏈是指對可能為 nil 的可選值查詢、呼叫屬性、下標和方法的過程。可選鏈返回兩個值:
如果可選值包含一個值,則呼叫其相關的屬性、方法和下標將返回相應的值。
如果可選值包含 nil 值,則其所有相關的屬性、方法和下標都將返回 nil。
由於對方法、屬性和下標的多個查詢被組合在一起,因此一個鏈的失敗會影響整個鏈,並導致返回 nil 值。
可選鏈作為強制解包的替代方案
可選鏈在可選值後使用“?”來呼叫屬性、方法或下標,前提是可選值返回某些值。
可選鏈“?” | 訪問方法、屬性和下標 可選鏈“!”強制解包。 |
“?”放在可選值之後,用於呼叫屬性、方法或下標。 | “!”放在可選值之後,用於呼叫屬性、方法或下標,強制解包值。 |
當可選值為 nil 時,優雅地失敗。 | 當可選值為 nil 時,強制解包會觸發執行時錯誤。 |
使用“!”的可選鏈程式
示例
class ElectionPoll { var candidate: Pollbooth? } class Pollbooth { var name = "MP" } let cand = ElectionPoll() let candname = cand.candidate!.name
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
main/main.swift:10: Fatal error: Unexpectedly found nil while unwrapping an Optional value Current stack trace: 0 libswiftCore.so 0x00007fd880a40dc0 _swift_stdlib_reportFatalErrorInFile + 112 1 libswiftCore.so 0x00007fd88070a191 <unavailable> + 1442193 2 libswiftCore.so 0x00007fd880709eb6 <unavailable> + 1441462 3 libswiftCore.so 0x00007fd880709caa <unavailable> + 1440938 4 libswiftCore.so 0x00007fd8807096d0 _assertionFailure(_:_:file:line:flags:) + 315 6 swift-frontend 0x000055a564ac0b3d <unavailable> + 26479421 7 swift-frontend 0x000055a563df4db9 <unavailable> + 13061561 8 swift-frontend 0x000055a563bc54c6 <unavailable> + 10769606 9 swift-frontend 0x000055a563bc19b6 <unavailable> + 10754486 10 swift-frontend 0x000055a563bc10a7 <unavailable> + 10752167 11 swift-frontend 0x000055a563bc341e <unavailable> + 10761246 12 swift-frontend 0x000055a563bc273d <unavailable> + 10757949 13 swift-frontend 0x000055a563a94a39 <unavailable> + 9521721 14 libc.so.6 0x00007fd880017d90 <unavailable> + 171408 15 libc.so.6 0x00007fd880017dc0 __libc_start_main + 128 16 swift-frontend 0x000055a563a94295 <unavailable> + 9519765 Stack dump: 0. Program arguments: /opt/swift/bin/swift-frontend -frontend -interpret main.swift -disable-objc-interop -color-diagnostics -new-driver-path /opt/swift/bin/swift-driver -empty-abi-descriptor -resource-dir /opt/swift/lib/swift -module-name main 1. Swift version 5.7.3 (swift-5.7.3-RELEASE) 2. Compiling with the current language version 3. While running user code "main.swift" Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var `LLVM_SYMBOLIZER_PATH` to point to it): /opt/swift/bin/swift-frontend(+0x551a103)[0x55a56869a103] /opt/swift/bin/swift-frontend(+0x551802e)[0x55a56869802e] /opt/swift/bin/swift-frontend(+0x551a48a)[0x55a56869a48a] /lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7fd880030520] /opt/swift/lib/swift/linux/libswiftCore.so(+0x160195)[0x7fd88070a195] /opt/swift/lib/swift/linux/libswiftCore.so(+0x15feb6)[0x7fd880709eb6] /opt/swift/lib/swift/linux/libswiftCore.so(+0x15fcaa)[0x7fd880709caa] /opt/swift/lib/swift/linux/libswiftCore.so($ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF+0x13b)[0x7fd88070980b] [0x7fd87ece717e] /opt/swift/bin/swift-frontend(+0x1940b3d)[0x55a564ac0b3d] /opt/swift/bin/swift-frontend(+0xc74db9)[0x55a563df4db9] /opt/swift/bin/swift-frontend(+0xa454c6)[0x55a563bc54c6] /opt/swift/bin/swift-frontend(+0xa419b6)[0x55a563bc19b6] /opt/swift/bin/swift-frontend(+0xa410a7)[0x55a563bc10a7] /opt/swift/bin/swift-frontend(+0xa4341e)[0x55a563bc341e] /opt/swift/bin/swift-frontend(+0xa4273d)[0x55a563bc273d] /opt/swift/bin/swift-frontend(+0x914a39)[0x55a563a94a39] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7fd880017d90] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7fd880017e40] /opt/swift/bin/swift-frontend(+0x914295)[0x55a563a94295] Illegal instruction (core dumped)
上述程式宣告“election poll”作為類名,幷包含“candidate”作為成員函式。子類宣告為“poll booth”,其成員函式“name”初始化為“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") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
Candidate name cannot be retreived
上述程式宣告“election poll”作為類名,幷包含“candidate”作為成員函式。子類宣告為“poll booth”,其成員函式“name”初始化為“MP”。對超類的呼叫是透過建立帶有可選“?”的例項“cand”來初始化的。由於其基類中未宣告值,因此儲存 nil 值,並由 else 處理程式塊在控制檯中列印。
為可選鏈定義模型類和訪問屬性
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") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
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") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
Area of circle is not specified
透過建立名為“circname”的例項來呼叫在 circle() 子類中宣告的 circleprint() 函式。如果函式包含某些值,則該函式將返回值;否則,它將透過檢查語句“if circname.print?.circleprint() != nil”返回一些使用者定義的列印訊息。
透過可選鏈訪問下標
可選鏈用於設定和檢索下標值,以驗證對該下標的呼叫是否返回值。“?”放在下標括號之前,用於訪問特定下標上的可選值。
示例 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.") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
Radius is not specified.
在上述程式中,未指定成員函式“radiusName”的例項值。因此,對函式的程式呼叫將僅返回 else 部分,而要返回值,則必須為特定成員函式定義值。
示例 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.") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
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])
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
Optional(35) Optional(78) Optional(78) Optional(101) Optional(90) Optional(44) Optional(56)
可以透過引用其下標值來訪問下標的可選值。可以訪問為 subscript[0]、subscript[1] 等。首先將“radius”的預設下標值賦值為 [35, 45, 78, 101],並將“Circle”賦值為 [90, 45, 56]]。然後將下標值更改為 Radius[0] 為 78,Circle[1] 為 45。
連結多級鏈
多個子類也可以透過可選鏈與其超類的方法、屬性和下標連結。
可以連結可選值的多個鏈
示例
如果檢索型別不是可選的,則可選鏈將返回一個可選值。例如,如果透過可選鏈檢索 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() if let radiusName = circname.print?[0].radiusname { print("The first room name is \(radiusName).") } else { print("Radius is not specified.") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
Radius is not specified.
在上述程式中,未指定成員函式“radiusName”的例項值。因此,對函式的程式呼叫將僅返回 else 部分,而要返回值,則必須為特定成員函式定義值。
如果檢索型別已經是可選的,則可選鏈也將返回一個可選值。例如,如果透過可選鏈訪問 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.") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
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") }
輸出
當我們在 playground 中執行上述程式時,我們將得到以下結果:
Area of circle is not specified