在我们使用objective-c表示字符串信息的时候,可以用下面方法书写。
NSString *str = @"秋恨雪"; str = nil;
因为objective-c是弱类型语言,所以这里的str既可以是具体的字符串也可以是nil。但到了Swift中就不可以了,因为Swift是类型安全的语言,一个String类型的变量不可能既能是具体的字符串,又可以为nil(更严格的说String类型的内容只能是字符串)。所以,在Swift中有了可选类型的概念。(其实这一概念也是“借鉴”于其他编程语言,比如C#,只不过在C#中称之为可空类型)
一、可选类型的定义
可选类型的格式: 类型名?
例如:
var phone: String?问号 "?" 表明phone 的值是可选的,可能是一个String,也可能不存在。
phone的值要么是String类型,要么是nil。
二、可选类型的应用
String有一个toInt方法,可以将字符串转为对应的整数。
有些字符串能转成整数: 比如 "123",可以转成 123。
有些字符串不能转成整数, 比如 "秋恨雪", 无法转成整数。
因此toInt方法的返回值是一个可选的Int类型(即 Int?)
所以转换结果如下:
let num = "123".toInt() // 123 let num2 = "秋恨雪".toInt() // nil注意: num和num2 都是 Int? 类型,而不是 Int类型。
三、可选类型的本质
Int? 其实是对Int的一层包装,它们是两种不同的数据类型。
var num: Int? = 10可以理解为num包含了 "Some" 和 "None" 这两个 "属性",而上面的操作只是将Int类型的10,包装到了Int? 中的 "Some" 中。示意图如下:
四、强制解包(拆包)
在可选类型的后面加个感叹号 "!",就可以将可选类型(包装)的值取出来,赋值给具体类型。
比如下面的写法:
var num: Int? = 10 var numValue: Int = num!其实就是将 "Some" 中的值取出来。示意图如下:
注意:如果可选类型(包装)的值不存在,即 "Some" 的值不存在,任然进行强制解包,会报错。
var num: Int? var numValue: Int = num!
错误信息:fatal error: unexpectedly found nil while unwrapping an Optional value.
因此,在强制解包之前,一定要先检查可选类型(包装)的值是否存在。
针对上面的情况,我们可以使用if语句来检测一个可选类型(包装)的值是否存在。例如:
if let num = "156".toInt() { println("num的值是\(num)") } else { println("num的值不存在") }
五、隐式解包(拆包)
默认情况下,如果想将可选类型(包装)的值赋给具体类型,比如将Int?的值赋给Int类型,需要使用感叹号 "!"
如果将可选类型声明为隐式解包。1. 不用再进行强制解包。
2. 能够自动解包:自动把可选类型(包装)的值取出来赋给具体类型。
隐式解包的声明只需将 "?" 改为 "!" 即可。例如:
var num: Int! = 20 var numValue: Int = num // 自动解包隐式解包的原理:
1. 相当于告诉编译器,这个可选类型的值一直都存在,绝对能取出里面的值。
2. 取值时不用手动加感叹号 "!",编译器会自动加上一个感叹号 "!" 。
六、"?" 和 "!"使用场景
1. 在Swift中闭包(如有疑问,请参照我上一章节《Swift:闭包(Closures)》)已经取代了block,定义一个闭包:
var testClosure: ((str1: String) -> Void)?
可以看出,这个闭包的类型后面有一个问号 "?",因为这个闭包属性很有可能为nil。
2. 在Swift中的IBOutlet的连线操作,就表明了这个控件是一定存在的。例如:
@IBOutlet weak var testLabel: UILabel!