深入解析Swift语言编程中的可选链

查询,调用属性,下标和方法上的一个可选可能 '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
(0)

相关推荐

  • Swift编程中的一些类型转换方法详解

    验证一个实例的类型'类型转换'在 Swift 语言编程中.它是用来检查实例类型是否属于特定超类或子类或其自己的层次结构定义. Swift 类型转换提供两个操作符:"is" 检查值的类型和 'as' 将类型值转换为不同的类型值. 类型转换还检查实例类型是否符合特定的协议一致性标准. 定义一个类层次结构 类型转换用于检查实例的类型或者它属于特定类型.此外,检查类和它的子类层次结构来检查并转换这些实例,使之作为一个相同的层次结构. 复制代码 代码如下: class Subjects {   

  • 详解Swift编程中下标的用法

    访问一个集合的元素成员,在类中的序列和列表,结构和枚举都可以使用下标.这些下标用于存储和使用索引来检索值.数组元素可使用如:someArray[index],在 Dictionary 实例及其后续成员元素的访问也可以使用如:someDicitonary[key]. 对于单一类型,下标范围可以从单一到多个声明.我们可以用适当的下标重载传递给下标索引值的类型.下标也可以根据输入数据类型声明范围从单一维度到多维度. 下标声明语法和用法 让我们回顾一下计算属性.下标也遵循计算属性相同的语法.对于查询类型

  • 解析Swift语言面相对象编程中的继承特性

    取大于形态的能力被定义为继承.一般一个类可以从另一个类继承属性和方法.类可以进一步划分到子类和超类. 子类:当一个类从另一个类继承属性,方法和功能被称为子类 超类:类包含属性,方法和功能被其它类继承称为超类 Swift 中类包含父类和调用访问方法,属性,功能和重写方法.另外,属性观察者也用于添加属性和修改所存储的或计算的特性的方法. 基类 一个类如果不从其它类继承方法,属性或功能,那么它被称为"基类". 复制代码 代码如下: classStudDetails{var stname:St

  • 深入解析Swift语言编程中的可选链

    查询,调用属性,下标和方法上的一个可选可能 'nil' 的过程被定义为可选的链.可选链返回两个值 如果可选包含一个值,然后调用其相关属性,方法和下标返回值 如果可选包含一个"nil"值,所有的相关属性,方法和下标返回nil 由于多种查询方法,属性和下标故障组合在一起,以一种链将影响到整个链,并导致产生 'nil' 的值. 可选链作为一种替代强制解包裹 可选链与可选值后指定"?"调用一个属性,方法或下标当可选的值返回一些值. 程序用于可选链 '!' 复制代码 代码如下

  • 解析Go语言编程中的struct结构

    struct和C语言的很相似,模拟出class的功能,但是不完全的!没有构造函数等! struct的申明 复制代码 代码如下: package main import "fmt" type Person struct {  Age  int  Name string } func main() {  //初始化两种  a := Person{}  a.Age = 2  a.Name = "widuu"  fmt.Println(a)  b := Person{   

  • 深入解析Go语言编程中slice切片结构

    数组转换成切片 复制代码 代码如下: a := [10]int{} fmt.Println(a)  s1 := a[:10]  //取前10个元素 [5:]取 5-最后的元素  fmt.Println(s1) slice测试 复制代码 代码如下: a := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'h'} sa := a[2:5] fmt.Println(string(sa)) sd1 := a[3:5] fmt.Println(string(sd1)) //看

  • 深入解析Go语言编程中的递归使用

    递归是以相似的方式重复项目的过程.同样适用于编程语言中,如果一个程序可以让你调用同一个函数被调用的函数,递归调用函数内使用如下. 复制代码 代码如下: func recursion() {    recursion() /* function calls itself */ } func main() {    recursion() } Go编程语言支持递归,即要调用的函数本身.但是在使用递归时,程序员需要谨慎确定函数的退出条件,否则会造成无限循环. 递归函数是解决许多数学问题想计算一个数阶乘

  • C语言编程中常见的五种错误及对应解决方案

    目录 1. 未初始化的变量 2. 数组越界 3. 字符串溢出 4. 重复释放内存 5. 使用无效的文件指针 前言: C 语言有时名声不太好,因为它不像近期的编程语言(比如 Rust)那样具有内存安全性.但是通过额外的代码,一些最常见和严重的 C 语言错误是可以避免的. 即使是最好的程序员也无法完全避免错误.这些错误可能会引入安全漏洞.导致程序崩溃或产生意外操作,具体影响要取决于程序的运行逻辑. 下文讲解了可能影响应用程序的五个错误以及避免它们的方法: 1. 未初始化的变量 程序启动时,系统会为其

  • 详解C语言编程中预处理器的用法

    预处理最大的标志便是大写,虽然这不是标准,但请你在使用的时候大写,为了自己,也为了后人. 预处理器在一般看来,用得最多的还是宏,这里总结一下预处理器的用法. #include <stdio.h> #define MACRO_OF_MINE #ifdef MACRO_OF_MINE #else #endif 上述五个预处理是最常看见的,第一个代表着包含一个头文件,可以理解为没有它很多功能都无法使用,例如C语言并没有把输入输入纳入标准当中,而是使用库函数来提供,所以只有包含了stdio.h这个头文

  • 解析Java线程编程中的线程安全与synchronized的使用

    一.什么时候会出现线程安全问题? 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量.一个对象.一个文件.一个数据库表等,而当多个线程同时访问同一个资源的时候,就会存在一个问题: 由于每个线程执行的过程是不可控的,所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错. 举个简单的例子: 现在有两个线程分别从网络上读取数据,然后插入一张数据库表中,要求不能插入重复的数据. 那么必然在插入数据的过程中存在两个操

  • 实例解析Java单例模式编程中对抽象工厂模式的运用

    定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 类型:创建类模式 类图: 抽象工厂模式与工厂方法模式的区别         抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象.他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构:而抽象工厂模式则是针对的多个产品等级结构.在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同

  • 实例解析C#设计模式编程中简单工厂模式的使用

    简单工厂模式的介绍 说到简单工厂,自然的第一个疑问当然就是什么是简单工厂模式了? 在现实生活中工厂是负责生产产品的,同样在设计模式中,简单工厂模式我们也可以理解为负责生产对象的一个类, 我们平常编程中,当使用"new"关键字创建一个对象时,此时该类就依赖与这个对象,也就是他们之间的耦合度高,当需求变化时,我们就不得不去修改此类的源码,此时我们可以运用面向对象(OO)的很重要的原则去解决这一的问题,该原则就是--封装改变,既然要封装改变,自然也就要找到改变的代码,然后把改变的代码用类来封

  • 解析C#网络编程中的Http请求

    本篇分享简单介绍C#中的Http请求,前几天帮朋友的项目封装ApiHelper,我粗糙的结果就如下,想想我真的是差的太远了.还有一位架构师也在封装这个Helper , 所以最后的结果当然是使用大牛的封装,这篇分享后,准备学习下他的封装,配置,错误处理机制等思想.不过这次也使我对C#网络编程了解的更多,算是一次学习经历吧.真心喜欢和老司机合作,下一阶段将会持续跟这位朋友学习项目底层的封装,和他谦虚的态度,有这样的机会也是幸运的. 你可以将其封装成自己的HttpHelper,经朋友建议,统一Http

随机推荐