簡介
這是一個Swift語言教程切平,基于最新的iOS 9磕谅,Xcode 7.3和Swift 2.2,會為你介紹Swift編程非吵璐浚基礎(chǔ)的內(nèi)容。從電腦如何工作的全程基本原理到語言結(jié)構(gòu)层释,你會足夠了解這門語言婆瓜,來處理數(shù)據(jù)和管理代碼的行為。
快速鏈接
- 一個下午讓你掌握Swift基礎(chǔ) ( 1/9 ) 編程本質(zhì) & Playground基礎(chǔ)
- 一個下午讓你掌握Swift基礎(chǔ) ( 2/9 ) 變量 & 常量
- 一個下午讓你掌握Swift基礎(chǔ) ( 3/9 ) 數(shù)字類型 & 操作
- 一個下午讓你掌握Swift基礎(chǔ) ( 4/9 ) 字符串
- 一個下午讓你掌握Swift基礎(chǔ) ( 5/9 ) 做判斷
- 一個下午讓你掌握Swift基礎(chǔ) ( 6/9 ) 重復(fù)步驟
- 一個下午讓你掌握Swift基礎(chǔ) ( 7/9 ) 函數(shù)
- 一個下午讓你掌握Swift基礎(chǔ) ( 8/9 ) 閉包
- 一個下午讓你掌握Swift基礎(chǔ) ( 9/9 ) 可選值
- Swift 初學(xué)者 ( 10/12 ) 數(shù)組
- Swift 初學(xué)者 ( 11/12 ) 字典
- Swift 初學(xué)者 ( 12/12 ) 集合
可選值
你目前遇到的所有變量和常量都有實(shí)際的值湃累。當(dāng)你有一個字符串變量的時候勃救,比如 var name,它有一個相關(guān)的字符串值治力,例如“張嘉夫”蒙秒。它可能是一個空字符串,像 “”宵统,但盡管如此晕讲,還是有一個可以訪問到的值。
那是 Swift 自帶的安全特色之一:如果說類型是 Int 或 String 那么就有一個實(shí)際的整數(shù)或字符串在那里马澈,有保證的瓢省。
這篇文章會為你介紹可選值(optionals)的概念,一個特殊的 Swift 類型痊班,不只可以表示一個值勤婚,也可以沒有值。在這篇文章的最后涤伐,你會知道為什么需要可選值馒胆,以及如何安全的使用它們。
介紹 nil
有時候凝果,有一個沒有值的值是很有用的祝迂。想象一個場景,你需要訪問一個人的認(rèn)證信息器净。你想要存儲這個人的名字型雳、年齡和職業(yè)。名字和年齡都是必須有值的東西—每個人都有山害。但不是每個人都有工作纠俭,所以職業(yè)這個值的缺失就是你需要處理的事情。
讓我們實(shí)際看看這個情況浪慌。
在不知道可選值的情況下柑晒,這是你可能去表示一個人的名字、年齡和職業(yè)的方式:
var name: String = "張嘉夫"
var age: Int = 23
var occupation: String = "軟件開發(fā)者 & 作家"
但如果我被解雇了呢眷射?也許我中了彩票然后再也不想工作了(我真的想3自蕖)。這時候能夠訪問一個不存在的值就會很有用了妖碉。
為什么你不能就用一個空的字符串呢涌庭?好吧,你可以欧宜!讓我們討論一下那樣會怎么做坐榆,以及為什么可選值是一個更好的選項。
標(biāo)記值
一個有效值冗茸,用來表示不存在的席镀,叫做標(biāo)記值(sentinel value)匹中。這是前一個例子里你的空字符串就會是這樣。
讓我們看一下另一個例子豪诲。假設(shè)你寫了一些代碼顶捷,從服務(wù)器上請求什么東西,那么你可以用一個變量來存儲服務(wù)器返回的任意錯誤代碼:
var errorCode: Int = 0
在成功的時候屎篱,你可以用零來表示沒有錯誤服赎。意味著 0 是標(biāo)記值。
就像職業(yè)的空字符串交播,這可以奏效重虑,但對于程序員有潛在的混淆的風(fēng)險。0 實(shí)際上可能是一個有效的錯誤代碼—也或許在未來會是秦士。無論怎么樣缺厉,你不能完全確定這是沒有錯誤的。
這兩種情況下隧土,如果有一個特殊類型可以表示值的缺失就會更好芽死。這樣什么時候有值什么時候沒有就很明確了。
Nil 表示值的缺失次洼,你會看到 Swift 如何用相當(dāng)優(yōu)雅的方式來直接把這個概念并入語言中关贵。
其他有一些編程語言只用標(biāo)記值。有一些卖毁,比如 Objective-C揖曾,有 ni 的概念,但僅僅是零的同義詞亥啦。只是另一個標(biāo)記值罷了炭剪。
Swift 介紹了一個全新的類型,叫做可選值來處理一個值可能是或不是 nil翔脱。這意味著如果你在處理一個非可選值類型奴拦,那么它就被保證了一定有值,不需要去擔(dān)心有沒有值届吁〈硌總是有的。相似的疚沐,如果你在用一個可選值類型暂氯,那你就必須要考慮 nil 情況了。它移除了使用標(biāo)記值帶來的歧義亮蛔。
介紹可選值
可選值是 Swift 對于同時表示值和值的缺失問題的解決方案痴施。一個可選值類型可以引用一個值或是 nil。
把可選值想象為一個盒子:它要么包含一個值,要么沒有辣吃。當(dāng)它沒有包含值的時候动遭,它被認(rèn)為包含了 nil。盒子本身總是存在神得;它一直在這里厘惦,你可以打開然后看看里面。
另一方面循头,字符串或整數(shù),周圍并沒有這個盒子炎疆。相關(guān)那里總有一個值卡骂,比如 “hello” 或 42。記住形入,非可選值類型確保有一個實(shí)際值全跨。
**注意:**學(xué)過物理的這時候可能會想起薛定諤的貓∫谒欤可選值和它有一點(diǎn)像浓若,除了這不是一個生死攸關(guān)的問題!
用下面的語法聲明可選值類型:
var errorCode: Int?
它和標(biāo)準(zhǔn)聲明之間的唯一區(qū)別就是類型末尾的問號蛇数。這個例子里挪钓,errorCode 是“ Int 可選值”。這意味著變量本身就像一個盒子耳舅,包含一個 Int 或 nil碌上。
設(shè)置值很簡單。你可以設(shè)置它為一個 Int浦徊,像這樣:
errorCode = 100
或者你可以設(shè)置它為 ni馏予,像這樣:
errorCode = nil
圖表可以幫助你形象化理解正在發(fā)生什么:
可選值盒子永遠(yuǎn)存在。當(dāng)你給變量賦值 100 的時候盔性,你在用值來填滿盒子煌茬。當(dāng)你給變量賦值 nil 的時候际长,你在清空盒子。
花幾分鐘想一下這個概念。用盒子的類比會是一個巨大的幫助岖常,在你讀完這篇文章剩下的部分的時候,然后開始使用可選值拂共。
迷你練習(xí)
創(chuàng)建一個叫做 myFavoriteSong 的 String 可選值唆途。如果你有一首最愛的歌,就把它設(shè)置為表示那首歌焕襟。如果你有不止一首或者沒有最愛的陨收,就設(shè)置可選值為 nil。
拆包可選值
有可選值一切都很好,但你應(yīng)該會好奇怎么看到盒子里面务漩,操作它所包含的值拄衰。
讓我們看看打印可選值的值得時候會發(fā)生什么:
let ageInteger: Int? = 23
print(ageInteger)
如下輸出:
Optional(30)
那不是你真正想要的—盡管如果仔細(xì)想一想,它還是有意義的饵骨。你的代碼輸出了盒子翘悉。結(jié)果說:“ ageInteger 是一個可選值,包含值 30”居触。
要看這個值類型如何區(qū)別于非可選值類型妖混,那就讓我們看看如果嘗試把 ageInteger 當(dāng)一個正常整數(shù)來使用會怎么樣:
print(ageInteger + 1)
代碼觸發(fā)了一個錯誤:
error: value of optional type 'Int?' not unwrapped; did you mean to use'!' or '?'?(錯誤:可選值類型 'Int?' 的值沒有被拆包;你是不是想使用 '!' 或 '?'轮洋?)
不正確是因為你嘗試把一個整數(shù)加到一個盒子上—不是盒子里面的值制市,而是盒子本身。這是沒有意義的弊予!
強(qiáng)制拆包
錯誤信息給了解決方案的指示:它告訴你可選值“沒有被拆包”祥楣。你需要從盒子里把值拆出來。就像過圣誕節(jié)汉柒!
來看看怎么做误褪。考慮如下聲明:
var authorName: String? = "張嘉夫"
你可以用兩種不同的方法來拆包可選值碾褂。第一種叫做強(qiáng)制拆包(force unwrapping)兽间,像這樣做:
var unwrappedAuthorName = authorName!
print("作者是\(unwrappedAuthor)")
變量名后面的感嘆號告訴編譯器你想看到盒子里面,并且把值拿出來正塌。這是結(jié)果:
作者是張嘉夫
很棒渡八!這就是你想要的。
使用詞語“強(qiáng)制”和感嘆號 ! 應(yīng)該給你傳達(dá)了一種危險感覺传货,這值得注意屎鳍。你應(yīng)該盡量少的使用強(qiáng)制拆包。要知道為什么问裕,考慮一下如果可選值不包含值得時候會發(fā)生什么:
authorName = nil
var unwrappedAuthorName = authorName!
print("作者是\(unwrappedAuthorName)")
這個代碼產(chǎn)生了如下運(yùn)行時錯誤:
fatal error: unexpectedly found nil while unwrapping an Optional value(致命錯誤:未料到地逮壁,拆包一個可選值的時候發(fā)現(xiàn)是 nil)
發(fā)生了這個錯誤是因為在你嘗試拆包變量的時候它沒有包含任何值。糟糕的是你是在運(yùn)行時得到這個錯誤粮宛,而不是編譯時窥淆,意味著只有在用非法的輸入執(zhí)行這部分代碼的時候才會發(fā)生,你才能注意到它巍杈。更糟糕的是忧饭,如果這個代碼在一個 app 內(nèi)部,運(yùn)行時錯誤會導(dǎo)致 app 崩潰筷畦!
怎么才能讓它安全呢词裤?
要在這里停止運(yùn)行時錯誤刺洒,你可以包住代碼,然后用一個檢查來拆包可選值吼砂,像這樣:
if authorName != nil {
var unwrappedAuthorName = authorName!
print("作者是\(unwrappedAuthorName)")
} else {
print("沒有作者逆航。")
}
if 語句檢查可選值是不是包含 nil。如果不是渔肩,意味著它包含一個你可以拆包的值因俐。
這個代碼現(xiàn)在安全了,但仍不失最佳狀態(tài)周偎。如果你依賴這個技術(shù)抹剩,每次你想拆包可選值的時候都要記住檢查 nil。這會開始變得單調(diào)乏味蓉坎,有一天你會忘記澳眷,然后再次導(dǎo)致運(yùn)行時錯誤的可能性。
然后回到繪圖板袍嬉!
If let 綁定
幸運(yùn)的是境蔼,Swift 包含了一個叫做 if let 綁定(binding)的特色灶平,讓你可以安全的訪問可選值里面的值伺通。像這樣使用:
if let unwrappedAuthorName: String = authorName {
print("作者是\(unwrappedAuthorName)")
} else {
print("沒有作者。")
}
你會立馬注意到這次沒有感嘆號了逢享,并且 unwrappedAuthorName 的類型是一個普通的 String罐监,不是一個可選值 String。
**注意:**一般的不會在 if let 語句指定拆包變量的類型瞒爬,這里是為了顯示清楚弓柱。
這個特殊語法擺脫了可選值類型。如果可選值包含值侧但,代碼執(zhí)行 if 語句的 if 那邊矢空,自動拆包 unwrappedAuthorName 變量,因為你知道這是安全的禀横,可以這么做屁药。
如果可選值不包含值,代碼執(zhí)行 if 語句的 else 那邊柏锄。這個例子里酿箭,unwrappedAuthorName 甚至都不存在。
你可以看到 if let 綁定與強(qiáng)制拆包相比有多么安全趾娃,你應(yīng)該任何可能的時候選擇它缭嫡。
你甚至可以一次拆包多個值,像這樣:
let authorName: String? = "張嘉夫"
let authorAge: Int? = 23
if let name: String = authorName,
age: Int = authorAge {
print("作者是\(age)歲的\(name)抬闷。")
} else {
print("沒有作者或沒有年齡妇蛀。")
}
這段代碼拆包了兩個值。它只在兩個可選值都包含值得時候才會執(zhí)行 if 部分的語句。
現(xiàn)在你知道如何安全的看進(jìn)一個可選值里面讥耗,并且取出值有勾,如果有的話。
迷你練習(xí)
- 使用之前的 myFavoriteSong 變量古程,使用 if let 綁定來檢查是否包含值蔼卡。如果是,print 這個值挣磨。如果沒有雇逞,print “我沒有一首喜歡的音樂∽氯梗”
- 把 myFavoriteSong 設(shè)置為當(dāng)前的相反面塘砸;也就是說,如果是 nil晤锥,就設(shè)置為一個字符串掉蔬,如果是一個字符串,就設(shè)置為 nil矾瘾。觀察你 print 的結(jié)果會有什么變化女轿。
Nil 合并
有一個終極和更常用的方式來拆包可選值。當(dāng)你想要取出可選值里的值壕翩,不論值是什么蛉迹,就用它—如果是 nil,就會使用一個默認(rèn)值放妈。這叫做 nil 合并(coalescing)北救。
這是它工作的方式:
var optionalInt: Int? = 10
var result: Int = optionalInt ?? 0
nil 合并發(fā)生在第二行,帶有兩個問號(??)芜抒。這行表示 result 會等于 optionalInt 里的值珍策,或者如果 optionalInt 包含的是 nil 就等于 0。
所以這個例子里宅倒,result 包含具體的 Int 值 10攘宙。
上面的代碼和下面等同:
var optionalInt: Int? = 10
var result: Int
if let unwrapped = optionalInt {
result = unwrapped
} else {
result = 0
}
設(shè)置 optionalInt 為 nil,像這樣:
optionalInt = nil
var result: Int = optionalInt ?? 0
現(xiàn)在你的 result 等于 0唉堪。
關(guān)鍵點(diǎn)
- Nil 表示值的缺失模聋。
- 非可選值變量和常量一定會有一個非 nil 值。
- 可選值(Optional)變量和常量就像盒子唠亚,可以包含一個值或是空的(nil)链方。
- 要處理可選值里的值,首先必須從可選值里拆包灶搜。
- 拆包可選值最安全的方式是使用 if let 綁定(binding)或 nil 合并祟蚀。避免強(qiáng)制拆包(forced unwrapping)工窍,它可能會導(dǎo)致一個運(yùn)行時錯誤。
接下來去哪兒前酿?
這就是可選值啦患雏,Swift 的一個核心特色,幫助讓語言更安全罢维,使用起來更簡單淹仑。你會發(fā)現(xiàn)代碼里會貫穿始終使用使用它們。他們幫你讓代碼更安全肺孵,通過保證明確處理值的缺失情況匀借。在你的 Swift 體驗中,你應(yīng)該會越來越欣賞它平窘。
特別是吓肋,你會在 10-12 篇教程中使用它們,并且在那里學(xué)習(xí)集合(collections)瑰艘。
挑戰(zhàn)
你已經(jīng)學(xué)習(xí)了可選值背后的理論是鬼,并且在實(shí)踐中見過他們了。現(xiàn)在輪到你搞一下了紫新!
挑戰(zhàn) A:你就是編譯器
下列哪個是有效語句均蜜?
var name: String? = "嘉夫"
var age: Int = nil
let distance: Float = 26.7
var middleName: String? = nil
挑戰(zhàn) B:分而治之
首先,創(chuàng)建一個函數(shù)弊琴,返回一個整數(shù)可以被另一個整數(shù)整數(shù)的次數(shù)兆龙。如果不能整除就返回 nil杖爽。命名函數(shù)為 divideIfWhole敲董。
然后,寫代碼嘗試拆包函數(shù)的可選值結(jié)果慰安。應(yīng)該有兩種情況:如果成功腋寨,print “Yep, 它整除 (answer) 次”,如果失敗化焕,print “除不盡 :[”萄窜。
最后,測試你的函數(shù):
- 10 除以 2撒桨。應(yīng)該 print “Yep查刻,它整除 5 次》锢啵”
- 10 除以 3穗泵。應(yīng)該 print “除不盡 :[”
提示 1:使用如下作為函數(shù)構(gòu)造的開始:
func divideIfWhole(value: Int, by divisor: Int)
你需要添加返回類型,這應(yīng)該是一個可選值谜疤!
提示 2:你可以使用模除操作符(%)來決定一個值是否能被另一個除盡佃延;回想一下现诀,這個操作返回兩個數(shù)字相除的余數(shù)。例如履肃,10 % 2 = 0 意味著 10 可以被 0 除盡仔沿,沒有余數(shù),但是 10 % 3 = 1 意味著 10 被 3 除了三次尺棋,有一個余數(shù)為 1封锉。
挑戰(zhàn) C:重構(gòu)與改善
上一個挑戰(zhàn)里,你用 if 語句寫的代碼膘螟。在這個挑戰(zhàn)里烘浦,重構(gòu)代碼,使用 nil 合并萍鲸。這次闷叉,所有情況都讓它輸出 “它除了 X 次”,但如果不是整除脊阴,那 X 就應(yīng)該是 0握侧。
挑戰(zhàn)和迷你練習(xí)源代碼
https://yunpan.cn/cBDRwNvgpHy4G (提取碼:f961)
介紹
歡迎來到Swift世界!Swift是一門蘋果在2014年夏天發(fā)布的編程語言嘿期。從那之后品擎,Swift發(fā)布了一個主要的版本跳躍,成為了開始在蘋果平臺:iOS备徐,OS X萄传,watchOS和tvOS開發(fā)的最簡單的方式。
誰適合這篇教程
這篇教程適合懂一點(diǎn)編程蜜猾、并且希望學(xué)習(xí)Swift的人秀菱。也許你已經(jīng)為網(wǎng)站寫過一些JavaScript代碼,或者用Python寫過一些簡短的程序蹭睡。這篇教程就是為你準(zhǔn)備的衍菱!你會學(xué)習(xí)到編程的基本概念,同時也會成為Swift語言小能手肩豁。
如果你是赤裸裸的編程新手脊串,這篇教程也是為你準(zhǔn)備的!教程里貫穿有簡短的鍛煉和挑戰(zhàn)來給你一些編程練習(xí)清钥,同時測試你的知識琼锋。
需要準(zhǔn)備什么
要看這篇教程,你需要準(zhǔn)備如下的東西:
- 一臺運(yùn)行OS X El Captian(10.11)的Mac祟昭,帶有最新發(fā)布的更新并且安裝了安全補(bǔ)丁缕坎。這樣你才能夠安裝需要的開發(fā)工具:最新版本的Xcode。
- Xcode 7.3 或更新的版本从橘。Xcode是用Swift寫代碼的主要開發(fā)工具念赶。最小也需要Xcode 7.3版本础钠,因為那個版本包含Swift 2.2。你可以免費(fèi)從Mac App Store下載Xcode的最新版本叉谜,這里:http://apple.co/1FLn51R旗吁。
如果你還沒有安裝Xcode最新版本,在繼續(xù)看下面的教程前要確定安裝停局。
如何使用這篇教程
每篇教程都會介紹觸手可及的話題理論很钓,伴隨大量Swift代碼來示范在學(xué)習(xí)的實(shí)際的應(yīng)用程序。
教程里的所有代碼都是平臺中立的董栽;這意味著不是為iOS码倦、OS X或任何其它平臺而特定。代碼在playgrounds里運(yùn)行锭碳,你在本篇中已經(jīng)學(xué)習(xí)了袁稽。
在剩下的教程里,你可以把代碼在自己的playground里輸入進(jìn)去擒抛。這樣你就可以和代碼“玩送破”(play around),做一些改變立即就能看見代碼運(yùn)行的結(jié)果歧沪。
剩下的教程里會貫穿實(shí)際小練習(xí)歹撒,都是簡短的練習(xí),關(guān)于觸手可及的主題诊胞。每篇的末尾也有挑戰(zhàn)暖夭,會有編程問題也會有長一點(diǎn)的代碼練習(xí)來測試你的知識。做完就能掌握大部分的Swift基礎(chǔ)知識撵孤。
教程更新
教程會隨Swift語言的更新而更新迈着,會發(fā)布在我的簡書和知乎專欄上,搜索“張嘉夫”即可關(guān)注我早直。
目錄
本教程從一些基礎(chǔ)工作開始來讓你起步:
- 第1篇寥假,編程本質(zhì) & Playground基礎(chǔ) - 這就是市框,到編程世界的入門介紹霞扬!你會從電腦和編程的預(yù)覽開始,然后剩余時間給Swift playground打個招呼枫振。
- 第2篇喻圃,變量 & 常量 - 你會學(xué)習(xí)到變量和常量,這是用來存儲數(shù)據(jù)的“地方”粪滤。你也會學(xué)習(xí)數(shù)據(jù)類型以及Swift如何追蹤數(shù)據(jù)類型并在代碼中進(jìn)行傳輸斧拍。
- 第3篇,數(shù)字類型 & 操作 - 你會從基礎(chǔ)的數(shù)字類型比如整形和浮點(diǎn)型數(shù)字開始杖小,當(dāng)然也包括布爾類型肆汹。也會看到一些在實(shí)際操作愚墓,從比較到算數(shù)操作如加減。
- 第4篇昂勉,字符串 - 用字符串來存儲文字-從按鈕里的文字到圖片的標(biāo)注到這篇教程全部的文字浪册,存儲這所有的一切!你會學(xué)習(xí)到string和character類型岗照,以及基于這些類型的一些常見操作村象。
在腦海中有基礎(chǔ)數(shù)據(jù)類型后,就該用那些數(shù)據(jù)做一些事情了:
- 第5篇攒至,做判斷 - 代碼不總是直接從頭運(yùn)行到尾厚者。你會學(xué)習(xí)在代碼里如何做判決并且設(shè)定情況來運(yùn)行某段代碼。
- 第6篇迫吐,重復(fù)步驟 - 繼續(xù)不要讓代碼直線運(yùn)行的主題库菲,你會學(xué)習(xí)到如何使用循環(huán)來重復(fù)某些步驟。
- 第7篇志膀,函數(shù) - 函數(shù)是Swift中用來構(gòu)建代碼的基礎(chǔ)建筑蝙昙。你會學(xué)習(xí)到如何定義函數(shù)來分組代碼到可復(fù)用單元中。
- 第8篇梧却,閉包(Closures) - 閉包和函數(shù)很接近奇颠。你會學(xué)習(xí)到如何使用它們來輕松傳遞代碼塊。
最后一篇會回到數(shù)據(jù):
- 第9節(jié)放航,可選值 - 這篇講可選值烈拒,Swift中的一種特殊類型,表示既有可能是一個真實(shí)的值也有可能沒有值广鳍。這篇的最后你會知道為什么要用可選值以及如何安全地使用它們荆几。
這些基礎(chǔ)會讓你快速開始Swift之路,做好接觸更高級編程主題的準(zhǔn)備赊时。