上一章Swift教程请查看:swift析构过程和自动引用计数(ARC)
在一个可能是“nil”的可选对象上查询、调用属性、下标和方法的过程被定义为可选链接,可选的链接返回两个值:
- 如果可选包含一个“值”,那么调用它的相关属性、方法和下标将返回值
- 如果可选项包含一个“nil”值,那么它的所有相关属性、方法和下标都将返回nil
由于对方法的多个查询,属性和下标被分组在一起,一个链的失败将影响整个链并导致’nil’值。
可选的链接作为强制展开的替代方法
可选链接是在‘?在可选值返回某些值时调用属性、方法或下标。
可选的链接“?” | 访问方法,属性和订阅可选链接’!强迫拆开包装 |
?放置在可选值之后以调用属性、方法或下标 | !是否放置在可选值之后以调用属性、方法或下标以强制展开值 |
当可选项为“nil”时,会优雅地失败 | 当可选参数为“nil”时,强制展开将触发运行时错误。 |
可选链接和’!’的程序
class ElectionPoll {
var candidate: Pollbooth?
}
lass Pollbooth {
var name = "MP"
}
let cand = ElectionPoll()
let candname = cand.candidate!.name
上面的程序声明’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("name \(candname)")
} else {
print("无法返回")
}
上面的程序声明’election
poll’作为类名,并包含’candidate’作为成员函数。子类声明为’poll booth’, ‘name’作为其成员函数,初始化为’MP’。对超类的调用是通过创建一个实例’cand’和一个可选的’?’来初始化的。因为这些值没有在基类中声明,所以‘nil’值由else处理程序块存储并打印在控制台中。
为可选的链接和访问属性定义模型类
Swift 语言还提供了可选链接的概念,将多个子类声明为模型类。这个概念对于定义复杂模型和访问属性、方法和下标子属性非常有用。
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: \(rectarea)")
} else {
print("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: \(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("is specified)")
} else {
print("not specified")
}
通过创建一个名为“circname”的实例来调用circle()子类中声明的函数circleprint()。该函数将返回一个值,如果它包含一些值,否则它将返回一些用户定义的打印消息,通过检查语句’if circname.print?.circleprint() != nil’。
通过可选链接访问下标
可选链接用于设置和检索下标值,以验证调用该下标是否返回值。”?’放在下标大括号前,以访问特定下标上的可选值。
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("number: \(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("name: \(radiusName).")
} else {
print("not specified.")
}
在上面的程序中,没有指定成员函数’radiusName’的实例值。因此,对函数的程序调用将只返回else部分,而要返回值,我们必须为特定的成员函数定义值。
访问可选类型的下标
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("number: \(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])
下标的可选值可以通过引用它们的下标值来访问。可用下标[0]、下标[1]等方式访问。’radius’的默认下标值首先被赋值为[35,45,78,101],而’Circle'[90, 45, 56]]。然后将下标值更改为半径[0]为78,圆[1]为45。
链接多级链接
多个子类还可以通过可选链接与其超类方法、属性和下标链接在一起。
可选的多重链接可以是链接的
如果检索类型不是可选的,可选链接将返回一个可选值。例如,如果字符串通过可选链接,它将返回String?Value。
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("number: \(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("name: \(radiusName).")
} else {
print("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: \(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("is specified)")
} else {
print("not specified")
}