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 運行上面的程序,得到以下結果。
fatal error: unexpectedly found nil while unwrapping an Optional value
0 swift 0x0000000103410b68 llvm::sys::PrintStackTrace(__sFILE*) + 40
1 swift 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 0x0000000102a85c39 llvm::JIT::runFunction(llvm::Function*, std::__1::vector
const&) + 329
6 swift 0x0000000102d320b3 llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::__1::vector
, std::__1::allocator
>, std::\_\_1::allocator
, std::\_\_1::allocator
> > > const&, char const\* const\*) + 1523 7 swift 0x000000010296e6ba swift::RunImmediately(swift::CompilerInstance&, std::\_\_1::vector
, std::\_\_1::allocator
>, std::\_\_1::allocator
, std::\_\_1::allocator
> > > const&, swift::IRGenOptions&, swift::SILOptions const&) + 1066 8 swift 0x000000010275764b frontend\_main(llvm::ArrayRef
, char const\*, void\*) + 5275 9 swift 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 -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' import Foundation
上述程序中聲明「 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 { println("Candidate name is \(candname)") } else { println("Candidate name cannot be retreived") }
當我們使用 playground 運行上面的程序,得到以下結果。
Candidate name cannot be retreived
上述程序中聲明「 election poll」 作爲類名,幷包含了作爲隸屬函數「candidate」。子類被聲明爲 「poll booth」 和 「name」 作爲被初始化爲 'MP' 的隸屬度函數。對超類的調用是通過創建一個實例,「cand」可選的初始化「?」。由於基類 'nil' 的值不聲明被存儲並打印在控制檯,由其他程序塊處理。
定義模型類的可選鏈接和訪問屬性
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() { println("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 { println("Area of rectangle is \(rectarea)") } else { println("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() { println("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 { println("Area of circle is specified)") } else { println("Area of circle is not specified") }
當我們使用 playground 運行上面的程序,得到以下結果。
Area of circle is not specified
該函數circleprint()在circle()子類中聲明通過創建名爲 「circname」 的一個實例來調用。函數會返回一個值 如果它包含一定的值則返回一些用戶定義的打印信息。否則會被檢查的語句 '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() { println("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 { println("The first room name is \(radiusName).") } else { println("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() { println("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 { println("Radius is measured in \(radiusName).") } else { println("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() { println("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]-- println(area["Radius"]?[0]) println(area["Radius"]?[1]) println(area["Radius"]?[2]) println(area["Radius"]?[3]) println(area["Circle"]?[0]) println(area["Circle"]?[1]) println(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。
鏈接鏈的多層次性
多個子類也可以憑藉其超類的方法,屬性和下標通過可選鏈接聯繫。
可選的多個鏈可以鏈接:
如果檢索類型是不可選的,可選鏈會返回一個可選值。例如,如果字符串通過可選鏈就會返回字符串?值
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() { println("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 { println("The first room name is \(radiusName).") } else { println("Radius is not specified.") }
當我們使用 playground 運行上面的程序,得到以下結果。
Radius is not specified.
在以上程序未指定隸屬函數 「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() { println("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 { println("The first room name is \(radiusName).") } else { println("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() { println("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 { println("Radius is measured in \(radiusName).") } else { println("Radius is not specified.") }
當我們使用 playground 運行上面的程序,得到以下結果。
Area of circle is not specified