学习Swift的人儿们,肯定对?与 !印象颇深。而这两个家伙一开始快把我给折磨死了,后来经过研究,浏览外国网站才有点想法,望有什么不足和不对之处能够得到大神们的指点~
一、其实最重要的要记住以下两点:
1.?
的几种使用场景:
1.声明Optional值变量
Optional其实是个enum
,里面有None
和Some
两种类型。其实所谓的nil就是Optional.None
, 非nil就 是Optional.Some
, 然后会通过Some(T)
包装(wrap)原始值。
2.用在对Optional值操作中,用来判断是否能响应后面的操作
在使用Optional值的时候需要在具体的操作,比如调用方法、属性、下标索引等前面需要加上一个?
,如果是 nil值,也就是Optional.None
,会跳过后面的操作不执行,如果有值,就是Optional.Some
,可能就会拆包 (unwrap),然后对拆包后的值执行后面的操作,来保证执行这个操作的安全性。
3.用于安全调用protocol的optional方法
4.使用 as? 向下转型(Downcast)
as?用于转换类型,如果不能转换成指定的类型,则设为nil,是安全的。
2.!一般用以下三种场景:
1.强制对Optional值进行拆包(unwrap)
不判断Optional值是否为nil,直接当成Optional.Some类型来进行强制拆包
2.声明Implicitly Unwrapped Optionals
值,一般用于类中的属性
一般用于声明一个必须有值的Optional类型的变量
3.使用as!强制转换类型
as!用于转换类型时,如果不能转换成指定类型,程序则崩溃
二、 代码详细讲解:
1.基于String类型使用!与?修饰的变量之间的区别
1.1 普通变量------String
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认 值,所以要求使用变量之前必须要对其初始化。如果在使用变量之前不进行初始化就会报错:
var hcp: String
// let hcpValue = hcp?.hashValue--普通值必须有初始值才能操作
hcp = "hcp"
let hcpValue = hcp.hashValue
print(hcpValue)
1.2 ?用于声明一个Optional的变量-----String?
//可选类型是用来解决对象变量或常量为空的情况
//可选类型后加“?”代表允许变量没有初始值,并设为nil
var hc : String?
print("hc is \(hc)") /// hc is nil
// print("hc is \(hc!)") //---这句话会崩溃---强制拆包
var hcc : String?
hcc = "hcc"
print("hcc is \(hcc)") /// hcc is Optional("hcc")
print("hcc is \(hcc!)") ///hcc is hcc
var str:String? = "1222"
//str = nil
var isEmpty = str?.hashValue
//一般不直接这样用当str = nil时就会崩溃
isEmpty = str!.hashValue
//一般这样做个安全判断或者str?.hashValue
if (str != nil){
print(str!.hashValue)
}
//isEmpty = str.hashValue //错误,可选类型不能直接操作
1.3 !用于声明Implicitly Unwrapped Optionals的变量-----String!
var hc1 : String!
print("hc is \(hc1)") // hc is nil---并没有操作只是打印所以不会崩溃
var hc2 : String!
hc2 = "hc" //--没有这句话程序会崩溃!
print("hc is \(hc2!)") // hc is hc
var b:String! = "hehe"
b = nil
//一般也不能这样操作,因为String!也可以设为nil,这时程序就会崩溃
let bisEmpty = b.hashValue //b后面也可以加!因为它是一个一定有值的可选类型
//一般这样做个安全判断或者b?.hashValue
if (b != nil){
print(b.hashValue)
}
print(bisEmpty)
2.as! 与 as?的区别
//as?-----as!
let dic = NSDictionary(object: 12, forKey: "SomeKey")
print(dic.objectForKey("SomeKey")) //dic.objectForKey是一个AnyObject类型
//as?---使用as?转换类型,如果不能转换为指定类型,会赋值nil,而不会崩溃
var optionalStr:String?
let value = dic.objectForKey("SomeKey") as? String
print("optionalStr is \(optionalStr)") // optionalStr is nil
//as!---使用as!转换类型,如果不能转换为指定类型,程序会崩溃
//optionalStr = dic.objectForKey("SomeKey") as! String //程序崩溃
//print("optionalStr is \(optionalStr)")
//optionalStr = dic.objectForKey("SomeKey") as! String? //程序崩溃,原因同上
//print("optionalStr is \(optionalStr)")
optionalStr = dic.objectForKey("SomeKey") as? String! // 虽然有!,但这个!是用于一个类型,而不是强制拆包, 所以这里不会崩溃
print("optionalStr is \(optionalStr)") // optionalStr is nil
optionalStr = dic.objectForKey("SomeKey") as? String!
print("optionalStr is \(optionalStr!)") // 程序崩溃,因为optionalStr为nil