Swift之 ? 和 !

轉(zhuǎn)載于: http://joeyio.com/ios/2014/06/04/swift---/

Swift語(yǔ)言使用var定義變量,但和別的語(yǔ)言不同,Swift里不會(huì)自動(dòng)給變量賦初始值,也就是說(shuō)變量不會(huì)有默認(rèn)值,所以要求使用變量之前必須要對(duì)其初始化。如果在使用變量之前不進(jìn)行初始化就會(huì)報(bào)錯(cuò):

var stringValue : String 
//error: variable 'stringValue' used before being initialized
//let hashValue = stringValue.hashValue
//                            ^
let hashValue = stringValue.hashValue

上面了解到的是普通值,接下來(lái)Optional值要上場(chǎng)了。經(jīng)喵神提醒,Optional其實(shí)是個(gè)enum,里面有None和Some兩種類型。其實(shí)所謂的nil就是Optional.None, 非nil就是Optional.Some, 然后會(huì)通過(guò)Some(T)包裝(wrap)原始值,這也是為什么在使用Optional的時(shí)候要拆包(從enum里取出來(lái)原始值)的原因, 也是PlayGround會(huì)把Optional值顯示為類似{Some "hello world"}的原因,這里是enum Optional的定義:

enum Optional<T> : LogicValue, Reflectable {
    case None
    case Some(T)
    init()
    init(_ some: T)

    /// Allow use in a Boolean context.
    func getLogicValue() -> Bool

    /// Haskell's fmap, which was mis-named
    func map<U>(f: (T) -> U) -> U?
    func getMirror() -> Mirror
}

聲明為Optional只需要在類型后面緊跟一個(gè)?即可。如:

var strValue: String?   //?相當(dāng)于下面這種寫法的語(yǔ)法糖
var strValue: Optional<String>  

上面這個(gè)Optional的聲明,意思不是”我聲明了一個(gè)Optional的String值”, 而是”我聲明了一個(gè)Optional類型值,它可能包含一個(gè)String值,也可能什么都不包含”,也就是說(shuō)實(shí)際上我們聲明的是Optional類型,而 不是聲明了一個(gè)String類型,這一點(diǎn)需要銘記在心。

建議再讀一遍上段文字。

一旦聲明為Optional的,如果不顯式的賦值就會(huì)有個(gè)默認(rèn)值nil。判斷一個(gè)Optional的值是否有值,可以用if來(lái)判斷:

if strValue {
    //do sth with strValue
}

然后怎么使用Optional值呢?文檔中也有提到說(shuō),在使用Optional值的時(shí)候需要在具體的操作,比如調(diào)用方法、屬性、下標(biāo)索引等前面需要加上一個(gè)?,如果是nil值,也就是Optional.None,會(huì)跳過(guò)后面的操作不執(zhí)行,如果有值,就是Optional.Some,可能就會(huì)拆包(unwrap),然后對(duì)拆包后的值執(zhí)行后面的操作,來(lái)保證執(zhí)行這個(gè)操作的安全性,比如:

let hashValue = strValue?.hashValue 

strValue是Optional的字符串,如果strValue是nil,則hashValue也為nil,如果strValue不為nil,hashValue就是strValue字符串的哈希值(其實(shí)也是用Optional wrap后的值)

另外,?還可以用在安全地調(diào)用protocol類型方法上,比如:

@objc protocol Downloadable {
    @optional func download(toPath: String) -> Bool;
}

@objc class Content: Downloadable {
    //download method not be implemented
}

var delegate: Downloadable = Downloadable()
delegate.download?("some path")

因?yàn)樯厦娴膁elegate是Downloadable類型的,它的download方法是optional,所以它的具體實(shí)現(xiàn)有沒(méi)有download方法是不確定的。Swift提供了一種在參數(shù)括號(hào)前加上一個(gè)?的方式來(lái)安全地調(diào)用protocol的optional方法。

另外如果你需要像下面這樣向下轉(zhuǎn)型(Downcast),可能會(huì)用到 as?:

if let dataSource = object as? UITableViewDataSource {
    let rowsInFirstSection  = dataSource.tableView(tableView, numberOfRowsInSection: 0)
}

到這里我們看到了?的幾種使用場(chǎng)景:
1.聲明Optional值變量
2.用在對(duì)Optional值操作中,用來(lái)判斷是否能響應(yīng)后面的操作
3.用于安全調(diào)用protocol的optional方法
4.使用 as? 向下轉(zhuǎn)型(Downcast)

另外,對(duì)于Optional值,不能直接進(jìn)行操作,否則會(huì)報(bào)錯(cuò):

//error: 'String?' does not have a member named 'hashValue'
//let hashValue = strValue.hashValue
//                ^        ~~~~~~~~~

let hashValue = strValue.hashValue

上面提到Optional值需要拆包(unwrap)后才能得到原來(lái)值,然后才能對(duì)其操作,那怎么來(lái)拆包呢?拆包提到了幾種方法,一種是Optional Binding, 比如:

if let str = strValue {
    let hashValue = str.hashValue
}

還有一種是在具體的操作前添加!符號(hào),好吧,這又是什么詭異的語(yǔ)法?!

直接上例子,strValue是Optional的String:

let hashValue = strValue!.hashValue 

這里的!表示“我確定這里的的strValue一定是非nil的,盡情調(diào)用吧” ,比如這種情況:

if strValue {
    let hashValue = strValue!.hashValue
}

{}里的strValue一定是非nil的,所以就能直接加上!,強(qiáng)制拆包(unwrap)并執(zhí)行后面的操作。 當(dāng)然如果不加判斷,strValue不小心為nil的話,就會(huì)出錯(cuò),crash掉。

考慮下這一種情況,我們有一個(gè)自定義的MyViewController類,類中有一個(gè)屬性是myLabel,myLabel是在viewDidLoad中進(jìn)行初始化。因?yàn)槭窃趘iewDidLoad中初始化,所以不能直接聲明為普通值:var myLabel : UILabel,因?yàn)榉荗ptional的變量必須在聲明時(shí)或者構(gòu)造器中進(jìn)行初始化,但我們是想在viewDidLoad中初始化,所以就只能聲明為Optional:var myLabel: UILabel?, 雖然我們確定在viewDidLoad中會(huì)初始化,并且在ViewController的生命周期內(nèi)不會(huì)置為nil,但是在對(duì)myLabel操作時(shí),每次依然要加上!來(lái)強(qiáng)制拆包(在讀取值的時(shí)候,也可以用?,謝謝iPresent在回復(fù)中提醒),比如:

myLabel!.text = "text"
myLabel!.frame = CGRectMake(0, 0, 10, 10)
...

對(duì)于這種類型的值,我們可以直接這么聲明:var myLabel: UILabel!, 果然是高(hao)大(gui)上(yi)的語(yǔ)法!, 這種是特殊的Optional,稱為Implicitly Unwrapped Optionals, 直譯就是隱式拆包的Optional,就等于說(shuō)你每次對(duì)這種類型的值操作時(shí),都會(huì)自動(dòng)在操作前補(bǔ)上一個(gè)!進(jìn)行拆包,然后在執(zhí)行后面的操作,當(dāng)然如果該值是nil,也一樣會(huì)報(bào)錯(cuò)crash掉。

var myLabel: UILabel! //!相當(dāng)于下面這種寫法的語(yǔ)法糖
var myLabel: ImplicitlyUnwrappedOptional<UILabel>
那么!大概也有兩種使用場(chǎng)景
1.強(qiáng)制對(duì)Optional值進(jìn)行拆包(unwrap)
2.聲明Implicitly Unwrapped Optionals值,一般用于類中的屬性

Swift是門新生的語(yǔ)言,我們有幸見(jiàn)證了它的誕生,激動(dòng)之余也在佩服蘋果大刀闊斧的推出一個(gè)新的語(yǔ)言替代一個(gè)已經(jīng)比較成熟語(yǔ)言的魄力,今天在知乎 日?qǐng)?bào)上看到一個(gè)回答是說(shuō)Swift是一門玩具語(yǔ)言,正當(dāng)想去吐槽,發(fā)現(xiàn)回答已經(jīng)被刪除了。個(gè)人認(rèn)為蘋果是很認(rèn)真的推出Swift的,從Swift的各種細(xì) 微的設(shè)計(jì)也能看的出來(lái)。

另外這兩個(gè)小符號(hào)就花費(fèi)了我不少的時(shí)間來(lái)理解,可能依然會(huì)有錯(cuò)誤和不妥之處,歡迎大家指正,本文旨在拋磚引玉。除此之外,Swift還有很多很棒的特性,WWDC 2014 會(huì)有四五個(gè)和Swift語(yǔ)言相關(guān)的Video,大家也可以去關(guān)注一下。

最后要感謝喵神的糾正了多處有問(wèn)題的地方,thx, have fun!

REF
The Swift Programming Language
Understanding Optionals in Swift

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift語(yǔ)言使用var定義變量,但和別的語(yǔ)言不同,Swift里不會(huì)自動(dòng)給變量賦初始值,也就是說(shuō)變量不會(huì)有默認(rèn)值,...
    子鍵_北京不眠夜閱讀 237評(píng)論 0 0
  • Swift語(yǔ)言使用var定義變量,但和別的語(yǔ)言不同,Swift里不會(huì)自動(dòng)給變量賦初始值,也就是說(shuō)變量不會(huì)有默認(rèn)值,...
    TomatosX閱讀 279評(píng)論 0 0
  • 關(guān)于 Swift 重要這個(gè)文檔所包含的準(zhǔn)備信息, 是關(guān)于開(kāi)發(fā)的 API 和技術(shù)的。這個(gè)信息可能會(huì)改變, 根據(jù)這個(gè)文...
    無(wú)灃閱讀 4,625評(píng)論 1 27
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 4,200評(píng)論 1 10
  • 1.元組 1.1什么是元組 在其他語(yǔ)言中很早就有元組這個(gè)概念, 但是對(duì)于OC程序員來(lái)說(shuō)這是一個(gè)新的概念官方定義:元...
    高俊閱讀 484評(píng)論 0 0

友情鏈接更多精彩內(nèi)容