Swift语言学习笔记一(可选类型? 和隐式可选类型!)

可选类型、隐式可选类型

在Swift 中可选类型是一个枚举类型(Enum),里面有None和非None两种类型,nil对应于Optional.None;非nil对应于Optional.Some(Wrapped),通过Some(Wrapped) 包装原始值,这也是为什么在使用Optional的时候要拆包(从Enum中的Some取出原始值)的原因,同理在PlayGround中会把Optional值显示为类似{Some”Hello World”},以下是Enum Optional的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
/// Construct a `nil` instance.
public init()
/// Construct a non-`nil` instance that stores `some`.
public init(_ some: Wrapped)
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
@warn_unused_result
@rethrows public func map<U>(@noescape f: (Wrapped) throws -> U) rethrows -> U?
/// Returns `nil` if `self` is nil, `f(self!)` otherwise.
@warn_unused_result
@rethrows public func flatMap<U>(@noescape f: (Wrapped) throws -> U?) rethrows -> U?
/// Create an instance initialized with `nil`.
public init(nilLiteral: ())
}

语法“?”使用

1.申明Optional值变量

1
2
3
4
var optionalName:String? = “Hello John”//定义一个可选变量optionalName并进行初始化
//optionalName = nil
print(optionalName)//输出 Optional("Hello John”)
print(optionalName!)//输出 "Hello John"

第一次输出和第二次输出的不同正好验证了上面的介绍,直接打印一个Optional变量,会打印出包装后的枚举值Some(Wrapped),如果要取得原始值必须进行拆包操作,即optionalName!拆包后打印出的值为原始值”Hello John”
如果打开第二行的注释,//optionalName = nil 相当于var optionalName:String,即不对optionalName进行初始化,第一次输出为nil,第二次输入的代码编译不过,因为这是一个可选变量,当变量为nil时,自动验证是否有可选的值,有则使用可选值,加上!访问符来访问optionalName变量,由于optionalName的值为nil,并没有包含一个实际值,所以抛出异常。可以用以下代码代替

1
2
3
4
5
6
7
8
9
10
11
12
//写法一
if (optionalName != nil) {
print(optionalName!)
}
//写法二
if let temp = optionalName {
print(temp)
}
//写法三
if var temp = optionalName {
print(temp)
}

2.用在对Optional值操作时,判断是否能响应后面的操作,且看示例

1
2
3
var button:UIButton?
let color = button?.tintColor
//解释:button 是可选变量,如果button是nil,则tintColor为nil;如果button不为nil,tintColor就是button的一个颜色属性值

语法”!”的使用

上面已经用到了!,主要是用来:

1.定义隐式可选变量

1
2
3
4
var button:UIButton! = UIButton()//定义一个隐式可选变量button,一定为非nil,在使用的时候不用每次都用?号判断是否为nil
//等价于
var button:UIButton!
button = UIButton()

2.拆包可选变量

可选类型变量,不能直接进行操作,否则会报错。因此要访问值就需要拆包。拆包有两种。
第一种:使用if let/var xxx =

1
2
3
4
var optionalName:String? = "Hello"
if let temp = optional {
//code
}

第二种:使用!号

1
2
var optionalName:String? = "Hello"
let hv = optionalName!.hashValue //这里的!表示这里的optionalName一定是非nil的,否则会报错

总结

在Swift中任何变量/常量的声明都必须带有初始值,否则就要声明为可选类型。
即var name:String 这样是编译不过的。必须改为带初始化的如:

1
var name:String = “John"

或者使用?或者!来约束,因此常常声明可选或隐式可选变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var name:String? //可选变量,在程序中不能确定该变量是否为nil的情况下使用
var name1:String!//隐式可选变量,在程序中可以确认该变量一定不为nil的情况下使用

//看看两种声明的具体用法就可以对比他们的不同之处
var button1:UIButton?
var button2:UIButton! = UIButton()
//注意!号的使用
if let tempBtn = button1{
button1!.frame = CGRectMake(0,0,50,40)
button1!.tintColor = UIColor.blackColor()
}
if let tempBtn = button2{
button2.frame = CGRectMake(0,0,50,40)
button2.tintColor = UIColor.blackColor()
}

感悟:

可选类型是Swift推出的全新语言类型,任何变量声明的同时必须进行初始化,否则就必须使用可选,在使用可选变量的时候赋值和使用都不方便,于是Swift推出隐式可选变量,使得申明的时候不用赋初值,使用过程中也不需要每次拆包以及验证是否为nil,但是付出的代价就是牺牲一定的安全性。