swfit进阶-08-Optional可选值

225 阅读5分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

  • 本文主要介绍swift中的Optional可选值

1. 认识Optional

我们开发中经常使用代表就是Optional,表示可以为空

class Person {

    

    var name:String?

    

}

let p = Person()

print(p.name as Any)

打印结果为nil,我们也可以使用Optional< T >表示

class Person {

    

    var name:Optional<String> = nil

    

}

let p = Person()

print(p.name as Any)

var name:String? 等同于 var name:Optional<String> = nil

  • 我们查看原码Optional.swift

image.png

它是一个枚举,可以表示为空。我们自己定义一个Optional

enum MyOptional<Value>{

    

    case none

    case some(Value)

}

func getOddValue(_ value:Int) -> MyOptional<Int> {

    

    if value%2 == 0 {

        return .some(value)

    }else{

        return .none

    }

}

//定义一个数组

var array = [1,2,3,4,5,6]


for element in array{

    

    let oddValue = getOddValue(element)

    

    array.remove(at: array.firstIndex(of: oddValue))

    

}

image.png

这个时候编译器就会检查我们当前的 value 会发现他的类型和系统编译器期望的类型不符,这 个时候我们就能使用 MyOptional 来限制语法的安全性。

for element in array{

    

    let oddValue = getOddValue(element)

    switch oddValue {

    case .some(let value):

    array.remove(at: array.firstIndex(of: value)!)

    case .none:

    print("\(element) vlaue not exist")

        

    }

    

}

我们通过枚举的匹配模式取出对应的值,达到类型一致,我们也可以把我们自定义的Optional换成Int?达到一样的效果。

image.png

这样我们其实是利用当前编译器的类型检查来达到语法书写层面的安全性

2. 可选值的绑定

上面的使用的匹配模式进行判断,但是如果比较多的话比较繁琐,我们可以这样

for element in array{

    

    let oddValue = getOddValue(element)

    if let value = oddValue {

        array.remove(at: array.firstIndex(of: value)!)

    }

    

}

用 if let 的方式来进行可选值绑定,当然我们在开发中也会经常使用守卫模式guard let 比如上面的列子中我们只想移除偶数2,就会嵌套逻辑的判断

image.png

我们使用guard 就可以直接进行判断,方便我们处理逻辑

image.png

3. 解包

  • 强制解包 我们知道我们的opyional是一个可选值,它可能有值,可能没有。我们使用表示强制解包,代表我们确定它一定有值

image.png 但是我们对于一个可能没值的可选值进行强制解包则会报错

image.png

  • 隐式解包 隐式解析可选类型是可选类型的一种,使用的过程中和非可选类型无异。它们之间唯一 的区别是,隐式解析可选类型是你告诉对 Swift 编译器,我在运行时访问时,值不会 为 nil

image.png

我们使用可选值的时候,修饰的变量告诉编译器我们这个肯定有值不需要在进行解包

image.png

我们使用xib的时候会默认解包告诉编译器,这个变量肯定存在

image.png

4. 空合并运算符

空合并运算符以 ?? 的形式来表达,它本质上是一个函数,其函数的定义如下:

public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)  rethrows -> T

( a ?? b ) 将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回 一个默认值 b 

  • 表达式 a 必须是 Optional 类型
  • 默认值 b 的类型必须要和 a 存储值的类型保持一致

image.png a存在的话就是a类型的值是可选值类型 image.png a不存在的话就是b类型的值

image.png a 必须是可选值才可以解包判断

5. 可选链

可选链表示我们可以在这个链上可以使用点语法或者下标进行访问,当我们对象是可选的则表示通过链进行访问的的对象,属性,或者方法可以为空。看个列子

image.png

当我们对一个定义ottional的属性或者对象调用它的方法时会进行判断是否存在,不存在的方法直接直接返回,相当于在oc中给一个nil对象发送消息,消息的接受者为nil直接返回什么也不做。而访问属性的时候相当于解包返回nil.

image.png

可选连

image.png

对于可选值类型的操作结果依然是可选值,可选链对于下标函数调用也适用

image.png

所以swift的可选值的使用是一种安全的体现,是我们的程序更加健壮。

6. 元类型、AnyClass、Self

我们开发中因为swift是一种安全语言我们经常会要转换类型下面进行区分

  • Any: 代表任意类型,包括funcation 类型或者 optional 类型(类似oc 中 id
  • AnyClass 代表任意实例的类型(类似oc中 class
  • AnyObject: 代表任意类的instance, 类的类型,仅类遵守的协议(类似oc中NSObject的实例,转换某一个实例对象)
  • T.self: 如果 T 是实例对象,返回的就是它本身,T 是类,那么返回的是 Metadata(类似oc中的isMemberOf,指向isa
  • T.Type: 一种类型,T.selfT.Type 类型 
  • type(of:): 用来获取一个值的动态类型

image.png

  • Self和self的区别:
protocol Copyable {
    func copy() -> Self
    func clamp(intervalToClamp: Self) -> Self
}

Self来说它只是表示特定类型,并且只能用在协议中或者作为某个类的方法返回值类型,而self在实例方法中代指当前实例,在类方法中则代指当前类

7. as , as?和 as!

  • as:把当前类型转换为其他类型

image.png

  • as?把当前类型转换为可选类型

image.png

  • as!把当前类型强制转换为其他类型,不同的话会造成崩溃

image.png

只有在明确相同类型的情况下使用as!否则使用as?

8. 总结

  • 可选值Optional本质是一个枚举,可能为none。可选值解包使用表示,但是一旦为空,就会崩溃。我们通常会对可选值进行绑定判断,使用if let判断,我们也可以使用gurad let 进行return
  • 可选值我们可以使用?? 进行判断,一般设置一些默认值
  • 对于Optional的对象我们可以使用点语法或者下标进行可选链的调用,对于这个链上某一个可选值的话,也不会报错,相当于消息接受者为空,直接返回
  • 类型范围Any>AnyClass>AnyObject ,T.self 以及T.type 根据实际选则。
  • 如果明确类型的话可以强制转换,否则使用as?可选类型。