- 快速教程
- 斯威夫特 - 主页
- 斯威夫特 - 概述
- 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 - 可选链接
对可能为“nil”的可选值进行查询、调用属性、下标和方法的过程被定义为可选链。可选链接返回两个值 -
如果可选包含“值”,则调用其相关属性、方法和下标将返回值
如果可选项包含“nil”值,则其所有相关属性、方法和下标都返回 nil
由于对方法、属性和下标的多个查询被分组在一起,一个链的失败将影响整个链并导致“nil”值。
可选链接作为强制展开的替代方案
可选链接在可选值之后用“?”指定 当可选值返回某些值时调用属性、方法或下标。
可选链接 '?' | 访问方法、属性和下标可选链接 '!' 强制展开 |
?放置在调用属性、方法或下标的可选值之后 | !放置在可选值之后以调用属性、方法或下标以强制解包值 |
当可选值为“nil”时优雅地失败 | 当可选值为“nil”时,强制展开会触发运行时错误 |
使用“!”进行可选链接的程序
class ElectionPoll { var candidate: Pollbooth? } lass Pollbooth { var name = "MP" } let cand = ElectionPoll() let candname = cand.candidate!.name
当我们使用 Playground 运行上述程序时,我们得到以下结果 -
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
上面的程序将“election poll”声明为类名,并包含“candidate”作为隶属函数。该子类被声明为“投票站”,“名称”为其成员函数,初始化为“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”作为隶属函数。该子类被声明为“投票站”,“名称”为其成员函数,初始化为“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”的实例值。因此,程序对函数的调用将仅返回其他部分,而要返回值,我们必须为特定的隶属函数定义值。
方案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)
下标的可选值可以通过引用其下标值来访问。它可以作为下标[0]、下标[1]等进行访问。“半径”的默认下标值首先指定为[35,45,78,101],“圆”的默认下标值为[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”的实例值。因此,程序对函数的调用将仅返回其他部分,而要返回值,我们必须为特定的隶属函数定义值。
如果检索类型已经是可选的,则可选链也将返回一个可选值。例如如果字符串?通过可选链访问它会返回 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