Swift之 ? 和 !ios
轉載於: http://joeyio.com/ios/2014/06/04/swift---/swift
Swift語言使用var定義變量,但和別的語言不一樣,Swift裏不會自動給變量賦初始值,也就是說變量不會有默認值,因此要求使用變量以前必需要對其初始化。若是在使用變量以前不進行初始化就會報錯:安全
var stringValue : String //error: variable 'stringValue' used before being initialized //let hashValue = stringValue.hashValue // ^ let hashValue = stringValue.hashValue
上面瞭解到的是普通值,接下來Optional值要上場了。經喵神提醒,Optional實際上是個enum
,裏面有None
和Some
兩種類型。其實所謂的nil就是Optional.None
, 非nil就是Optional.Some
, 而後會經過Some(T)
包裝(wrap)原始值,這也是爲何在使用Optional的時候要拆包(從enum裏取出來原始值)的緣由, 也是PlayGround會把Optional值顯示爲相似{Some "hello world"}
的緣由,這裏是enum Optional的定義:app
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只須要在類型後面緊跟一個?
便可。如:ide
var strValue: String? //?至關於下面這種寫法的語法糖 var strValue: Optional<String>
上面這個Optional的聲明,意思不是」我聲明瞭一個Optional的String值」, 而是」我聲明瞭一個Optional類型值,它可能包含一個String值,也可能什麼都不包含」,也就是說實際上咱們聲明的是Optional類型,而 不是聲明瞭一個String類型,這一點須要銘記在心。ui
建議再讀一遍上段文字。spa
一旦聲明爲Optional的,若是不顯式的賦值就會有個默認值nil。判斷一個Optional的值是否有值,能夠用if來判斷:設計
if strValue { //do sth with strValue }
而後怎麼使用Optional值呢?文檔中也有提到說,在使用Optional值的時候須要在具體的操做,好比調用方法、屬性、下標索引等前面須要加上一個?
,若是是nil值,也就是Optional.None
,會跳事後面的操做不執行,若是有值,就是Optional.Some
,可能就會拆包(unwrap),而後對拆包後的值執行後面的操做,來保證執行這個操做的安全性,好比:code
let hashValue = strValue?.hashValue
strValue是Optional的字符串,若是strValue是nil,則hashValue也爲nil,若是strValue不爲nil,hashValue就是strValue字符串的哈希值(其實也是用Optional wrap後的值)blog
另外,?還能夠用在安全地調用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")
由於上面的delegate是Downloadable類型的,它的download
方法是optional,因此它的具體實現有沒有download
方法是不肯定的。Swift提供了一種在參數括號前加上一個?
的方式來安全地調用protocol的optional方法。
另外若是你須要像下面這樣向下轉型(Downcast),可能會用到 as?
:
if let dataSource = object as? UITableViewDataSource { let rowsInFirstSection = dataSource.tableView(tableView, numberOfRowsInSection: 0) }
到這裏咱們看到了
?
的幾種使用場景:
1.聲明Optional值變量
2.用在對Optional值操做中,用來判斷是否能響應後面的操做
3.用於安全調用protocol的optional方法
4.使用 as? 向下轉型(Downcast)
另外,對於Optional值,不能直接進行操做,不然會報錯:
//error: 'String?' does not have a member named 'hashValue' //let hashValue = strValue.hashValue // ^ ~~~~~~~~~ let hashValue = strValue.hashValue
上面提到Optional值須要拆包(unwrap)後才能獲得原來值,而後才能對其操做,那怎麼來拆包呢?拆包提到了幾種方法,一種是Optional Binding
, 好比:
if let str = strValue { let hashValue = str.hashValue }
還有一種是在具體的操做前添加!
符號,好吧,這又是什麼詭異的語法?!
直接上例子,strValue是Optional的String:
let hashValue = strValue!.hashValue
這裏的!
表示「我肯定這裏的的strValue必定是非nil的,盡情調用吧」 ,好比這種狀況:
if strValue { let hashValue = strValue!.hashValue }
{}裏的strValue必定是非nil的,因此就能直接加上!,強制拆包(unwrap)並執行後面的操做。 固然若是不加判斷,strValue不當心爲nil的話,就會出錯,crash掉。
考慮下這一種狀況,咱們有一個自定義的MyViewController
類,類中有一個屬性是myLabel
,myLabel是在viewDidLoad中進行初始化。由於是在viewDidLoad中初始化,因此不能直接聲明爲普通值:var myLabel : UILabel
,由於非Optional的變量必須在聲明時或者構造器中進行初始化,但咱們是想在viewDidLoad中初始化,因此就只能聲明爲Optional:var myLabel: UILabel?
, 雖然咱們肯定在viewDidLoad中會初始化,而且在ViewController的生命週期內不會置爲nil,可是在對myLabel操做時,每次依然要加上!
來強制拆包(在讀取值的時候,也能夠用?
,謝謝iPresent在回覆中提醒),好比:
myLabel!.text = "text" myLabel!.frame = CGRectMake(0, 0, 10, 10) ...
對於這種類型的值,咱們能夠直接這麼聲明:var myLabel: UILabel!
, 果真是高(hao)大(gui)上(yi)的語法!, 這種是特殊的Optional,稱爲Implicitly Unwrapped Optionals
, 直譯就是隱式拆包的Optional,就等於說你每次對這種類型的值操做時,都會自動在操做前補上一個!
進行拆包,而後在執行後面的操做,固然若是該值是nil,也同樣會報錯crash掉。
var myLabel: UILabel! //!至關於下面這種寫法的語法糖 var myLabel: ImplicitlyUnwrappedOptional<UILabel>
那麼
!
大概也有兩種使用場景
1.強制對Optional值進行拆包(unwrap)
2.聲明Implicitly Unwrapped Optionals
值,通常用於類中的屬性
Swift是門新生的語言,咱們有幸見證了它的誕生,激動之餘也在佩服蘋果大刀闊斧的推出一個新的語言替代一個已經比較成熟語言的魄力,今天在知乎 日報上看到一個回答是說Swift是一門玩具語言,正當想去吐槽,發現回答已經被刪除了。我的認爲蘋果是很認真的推出Swift的,從Swift的各類細 微的設計也能看的出來。
另外這兩個小符號就花費了我很多的時間來理解,可能依然會有錯誤和不妥之處,歡迎你們指正,本文旨在拋磚引玉。除此以外,Swift還有不少很棒的特性,WWDC 2014 會有四五個和Swift語言相關的Video,你們也能夠去關注一下。
最後要感謝喵神的糾正了多處有問題的地方,thx, have fun!