📜  Swift-可选链接

📅  最后修改于: 2020-12-25 04:39:55             🧑  作者: Mango


在可选的可能为“ nil”的查询中调用,调用属性,下标和方法的过程被定义为可选链接。可选链接返回两个值-

  • 如果可选包含“值”,则调用其相关属性,方法和下标返回值

  • 如果可选的所有相关属性都包含“ nil”值,则方法和下标将返回nil

由于对方法,属性和下标的多次查询归为一组,因此对一个链的失败会影响整个链,并导致“零”值。

可选链接作为强制展开的替代方法

可选链接在可选值之后用’?’指定当可选值返回一些值时调用属性,方法或下标。

Optional Chaining ‘?’ Access to methods,properties and subscriptsOptional Chaining ‘!’ to force Unwrapping
? is placed after the optional value to call property, method or subscript ! is placed after the optional value to call property, method or subscript to force unwrapping of value
Fails gracefully when the optional is ‘nil’ Forced unwrapping triggers a run time error when the optional is ‘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<:__1::basic_string std::__1::allocator="">,
std::__1::allocator<:__1::basic_string std::__1::allocator=""> > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<:__1::basic_string std::__1::allocator="">, std::__1::allocator<:__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 <

上面的程序将“ 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")
}

当我们使用游乐场运行上述程序时,我们得到以下结果-

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")
}

当我们使用游乐场运行上述程序时,我们得到以下结果-

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

通过创建名为“ 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.")
}

当我们使用游乐场运行上述程序时,我们得到以下结果-

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)

下标的可选值可以通过引用其下标值来访问。可以作为下标[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.")
}

当我们使用游乐场运行上述程序时,我们得到以下结果-

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.")
}

当我们使用游乐场运行上述程序时,我们得到以下结果-

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