Swift纠结:optional 的!和?
optional
本文为对 swift自我学习的理解,如有错误,还望纠正。
Optional的定义:
它的特点就和它的名字一样:可选值类型。可以有值,也可以没有值,当它没有值时,就是nil。
一、与 object-c区别:
- 在Objective-C中,只有对象才能为nil
而在Swift里,当基础类型(整形、浮点、布尔等)没有值时,也是nil,而不是一个初始值,没有初始值的值,是不能使用的。
二、optional的使用
var str: String?
理解optional:
- Optional值未经初始化虽然为nil,但普通变量没有。即:optional 为 nil 状态(无值状态) 与确定值(值为多少取决于你付的值)状态。而其他类型相当于是 空值(像 C 的野指针,会报错)和确定值。
var str: String? //未被初始化,但是是一个Optional类型,为nil
str //输出nil
var str2: String //未被初始化,也不是Optional类型
str2 //使用时出错
optional结构:
var str: String? = "Hello World!" //未被初始化,但是是一个Optional类型,为nil
println(str) //输出 : {Some "Hello World!"}
可看出 value 其实存储于一个枚举中,要访问其值要拆包才行.
结构如下:
enum Optional<T> : Reflectable, NilLiteralConvertible {
case None //swift 会省略 break;要进入下一个 case 要在末尾加 fallthrough
//此处有个省略的break;(我的理解)
case Some(T)
init()
init(_ some: T)
/** 此处我还未理解=_= **/
func map<U>(f: (T) -> U) -> U?
func getMirror() -> MirrorType
static func convertFromNilLiteral() -> T?
}
可见,nil=>Optional.None,即没有值。当有值时就是被Some<T>包装的真正的值,所以我们拆包的动作其实就是将Some里面的值取出来。
三、Optional的拆包。
1.显式拆包
在变量后添加 ! 即可快捷拆包(还有另一种正常方式,比较麻烦,一般不会使用,所以就不列出了)
var str: String? = "Hello World!"
println(str) //输出: {Some "Hello World!"}
println(str!) //输出: Hello World!
2.隐式拆包
var str: String! = "Hello World!" //注意 String 后的!号
println(str) //Hello World!
但不建议这种做法,从上可得,若 str 无值时会直接报错。可见其实 swift 是不希望我们这样使用的,所以特地有一个可选择类型加强评断的逻辑性。
使用前提:确定变量定会有值时使用。
3.optional binding (判断自动解包)
当在判断语句中赋值 optional 类型给,临时常量(或变量),会自动解包(不用加!号)
var count: Int?
count = 100
if let validCount = count { // optional binding ,不用加!解包,自动解包
"count is " + String(validCount) //count is 100而不是{some 100}
} else {
"nil"
}
4.optional chaining(可选判断链)
class man {
var pet: Pet?
}
class Pet {
var name: String
var Toy: Toy?
init (name: String) {
self.name = name
}
}
如上,某人的可能有宠物狗,并且宠物狗可能会有自己的玩具.根据上面为了安全要如下binding:
let Tom = man()
Tom.pet = Pet(name: "dog")
Tom.pet?.Toy = Toy(name: "toy")
if let pet = Tom.pet { //判断是否有宠物
if let toy = pet.Toy { //判断有无玩具
toy.name //经过多重判断才能确保有值
}
}
以上,两层数就要解包两次,N 层呢? 所以出了 optional chaining 只要判断最里层有无,会自动判断中间层是否为 nil ,只要其中一层为 nil ,则整体为 nil.即:
if let toy = Tom.pet?.Toy { //最里层的 Toy,中间层 pet?
toy.name
}
代码简单多了~
老规矩,学习原址:http://blog.csdn.net/zhangao0086/article/details/38640209