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的定義:
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只需要在型別後面緊跟一個?
即可。如:
var strValue: String? //?相當於下面這種寫法的語法糖
var strValue: Optional<String>
上面這個Optional的宣告,意思不是”我宣告瞭一個Optional的String值”, 而是”我宣告瞭一個Optional型別值,它可能包含一個String值,也可能什麼都不包含”,也就是說實際上我們宣告的是Optional型別,而不是宣告瞭一個String型別,這一點需要銘記在心。
建議再讀一遍上段文字。
一旦宣告為Optional的,如果不顯式的賦值就會有個預設值nil。判斷一個Optional的值是否有值,可以用if來判斷:
if strValue {
//do sth with strValue
}
然後怎麼使用Optional值呢?文件中也有提到說,在使用Optional值的時候需要在具體的操作,比如呼叫方法、屬性、下標索引等前面需要加上一個?
,如果是nil值,也就是Optional.None
,會跳過後面的操作不執行,如果有值,就是Optional.Some
,可能就會拆包(unwrap),然後對拆包後的值執行後面的操作,來保證執行這個操作的安全性,比如:
let hashValue = strValue?.hashValue
strValue是Optional的字串,如果strValue是nil,則hashValue也為nil,如果strValue不為nil,hashValue就是strValue字串的雜湊值(其實也是用Optional wrap後的值)
另外,?還可以用在安全地呼叫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!
REF
相關文章
- Swift之花括號Swift
- Swift:字元和字串Swift字元字串
- 窺探Swift之別具一格的Struct和ClassSwiftStruct
- Swift 的強大之處Swift
- OC和Swift混編Swift
- Swift 5 字串插值之美Swift字串
- 玩轉swift — UIKit 之 UIView(1)SwiftUIView
- Swift之SQLite的基礎使用SwiftSQLite
- LeetCode之加一-SwiftLeetCodeSwift
- # Swift 集合型別之迭代器Swift型別
- Swift 造輪子之自制 HUDSwift
- 進階-Swift和OC混編生成 swift pod私有庫Swift
- Swift和Objective-C混合程式設計——Swift呼叫OCSwiftObject程式設計
- Swift和Objective-C混合程式設計——OC呼叫SwiftSwiftObject程式設計
- swift 區間運算子(... 和 ..Swift
- Swift(一)常量和變數Swift變數
- Swift和Objective C比較SwiftObject
- swift 中的 AnyObject 和 AnySwiftObject
- Swift和Kotlin區別SwiftKotlin
- 窺探Swift之協議(Protocol)和委託代理(Delegate)回撥的使用Swift協議Protocol
- Swift筆記之變數講解Swift筆記變數
- Swift Web 開發之 Vapor – 路由(二)SwiftWebVapor路由
- Swift 之刪除清空 webView 的 CookiesSwiftWebViewCookie
- Swift 4 踩坑之 Codable 協議Swift協議
- swift 學習筆記之陣列Swift筆記陣列
- OC和Swift混編經驗Swift
- Swift中Class和Struct異同SwiftStruct
- Swift-類和結構體Swift結構體
- iOS UMeng OC和Swift混編iOSSwift
- Objective-C和Swift混編ObjectSwift
- Swift中的值和指標Swift指標
- Swift相簿選擇和拍照功能Swift
- Swift中的CGRect、CGSize和CGPointSwift
- swift之與h5之間的互動(一)SwiftH5
- Swift 5 之後 "Method Swizzling"?Swift
- Swift Web 開發之 Vapor – 模版 Leaf(三)SwiftWebVapor
- Swift之struct二進位制大小分析SwiftStruct
- Swift之集合型別 (Collection Types)(集合篇)Swift型別