在數(shù)組的方括號(hào)內(nèi)必須寫上類型,或者在Array后面的尖括號(hào)<>內(nèi)寫上類型。
對(duì)于字典而言,你一共需要提供兩個(gè)類型,一個(gè)用于鍵,而另一個(gè)用于值。
Swift要求所有的變量和常量都必須有值。你可以在聲明它們的時(shí)候給它們指定一個(gè)值,也可以通過(guò)init方法給它們分配值。
有時(shí),你需要一個(gè)變量可以沒(méi)有值,這種情況,你需要將變量聲明為可選型:
var checklistToEdit: Checklist?
你不能直接使用這種類型的變量;你必須在使用它們之前,偵測(cè)一下其中是否有值,這個(gè)行為就叫做可選型解包:
if let checklist = checklistToEdit {
// “checklist” now contains the real object
} else {
// the optional was nil
}
下面例子中的變量age就是一個(gè)可選型,因?yàn)闆](méi)有任何保證說(shuō)字典中存在一個(gè)名為"Jony Ive"的鍵,所以age的類型是Int?,而不是Int:
if let age = dict["Jony Ive"] {
// 使用age變量
}
如果你100%的確定字典中存在一個(gè)叫做"Jony Ive"的鍵的話,那么你就可以對(duì)age變量進(jìn)行強(qiáng)制解包:
var age = dict["Jony Ive"]!
你使用感嘆號(hào)來(lái)通知Swift,‘這個(gè)可選型不會(huì)為nil,我用我的名譽(yù)打賭!’,當(dāng)然,如果你錯(cuò)了的話,這個(gè)變量的值為nil,那么app就會(huì)掛掉,你也就名譽(yù)掃地了,所以你在使用強(qiáng)制解包的時(shí)候一定要小心。
另一種稍微安全點(diǎn)的強(qiáng)制解包方式叫做可選型鏈接。例如,下面的語(yǔ)句會(huì)在navigationController為nil時(shí)把a(bǔ)pp掛掉。
navigationController!.delegate = self
但是像這樣做則不會(huì)把a(bǔ)pp掛掉:
navigationController?.delegate = self
位于問(wèn)號(hào)后面的任何東西,都會(huì)在navigationController為nil時(shí)把它忽視掉。這個(gè)使用問(wèn)號(hào)強(qiáng)制解包的語(yǔ)句等價(jià)于下面的語(yǔ)句:
if navigationController != nil {
navigationController!.delegate = self
}
在聲明可選型的時(shí)候,也可以用感嘆號(hào)來(lái)代替問(wèn)號(hào),這樣就是一個(gè)隱式解包可選型了:
var dataModel: DataModel!
這樣的變量會(huì)帶來(lái)潛在的危險(xiǎn),因?yàn)槟憧梢韵蚴褂贸R?guī)變量那樣直接使用它,并不需要先解包。如果它的值為空,那么app就掛了,而常規(guī)變量為空時(shí),編譯器會(huì)提示你怎么做。
可選型平時(shí)被包裹起來(lái),以避免app崩潰,但是使用了感嘆號(hào)以后,就解除了可選型的安全級(jí)別。
然而,有時(shí)使用隱式解包可選型比使用可選型要方便一些。當(dāng)你無(wú)法給一個(gè)變量初始值,也無(wú)法用init方法對(duì)其初始化的時(shí)候,你就會(huì)需要到這種隱式解包可選型。
如果你給了一個(gè)變量一個(gè)值后,就不應(yīng)該在使它為nil,如果一個(gè)變量可以從有值變?yōu)閚il,那么你最好還是使用用問(wèn)號(hào)聲明的可選型。
方法與函數(shù)(Methods and functions)
你已經(jīng)學(xué)習(xí)過(guò)這樣的一種對(duì)象了,它是所有app的基礎(chǔ)組成部分,同時(shí)具有數(shù)據(jù)和功能。實(shí)例變量及常量提供數(shù)據(jù),方法提供功能。
當(dāng)你調(diào)用一個(gè)方法,app就會(huì)跳轉(zhuǎn)到方法中,逐條的執(zhí)行其中的語(yǔ)句,當(dāng)方法中最后一條語(yǔ)句被執(zhí)行完畢后,app就會(huì)會(huì)到之前離開(kāi)的地方:
let result = performUselessCalculation(314)
print(result)
...
func performUselessCalculation(_ a: Int) -> Int {
var b = Int(arc4random_uniform(100))
var c = a / 2
return (a + b) * c
}
方法經(jīng)常會(huì)返回一個(gè)值給調(diào)用者,比如一個(gè)計(jì)算結(jié)果或者從一個(gè)集合中找到的一個(gè)對(duì)象。返回值的類型會(huì)寫在->符號(hào)的后面。在上面的例子中,返回值的類型是Int。如果不存在->這個(gè)符號(hào),那么就是說(shuō)這個(gè)方法不返回任何值。
方法就是屬于某一特定對(duì)象的函數(shù),Swift中也存在獨(dú)立的函數(shù),比如print()或者arc4random_uniform()。
函數(shù)和方法的工作原理一樣,一個(gè)可重復(fù)使用的功能塊,但是函數(shù)不屬于任何對(duì)象。像這種函數(shù)也被稱為自由函數(shù)或者全局函數(shù)。
下面是一些關(guān)于方法的例子:
// 這個(gè)方法沒(méi)有返回值及參數(shù)的方法
override func viewDidLoad()
// 這個(gè)方法有一個(gè)slider參數(shù),但是一樣沒(méi)有返回值
// 關(guān)鍵字@IBAction意味著這個(gè)方法可以被連接到界面建造器的控件上
@IBAction func sliderMoved(_ slider: UISlider)
// 這個(gè)方法沒(méi)有參數(shù),但是有一個(gè)Int型的返回值
func countUncheckedItems() -> Int
// 這個(gè)方法有兩個(gè)參數(shù),cell和item,但是沒(méi)有返回值
// 注意一下,第一個(gè)參數(shù)有一個(gè)外部名稱for,而第二個(gè)參數(shù)有一個(gè)外部名稱with
func configureCheckmarkFor(for cell: UITableViewCell,
with item: ChecklistItem)
// 這個(gè)方法有兩個(gè)參數(shù), tableView和section. 并且有一個(gè)Int型的返回值。
// 第一個(gè)參數(shù)前的下劃線代表這個(gè)參數(shù)沒(méi)有外部名稱。
override func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int
// 這個(gè)方法有兩個(gè)參數(shù), tableView和indexPath.
// 問(wèn)號(hào)代表它返回一個(gè)為可選型的IndexPath對(duì)象。
override func tableView(_ tableView: UITableView,
willSelectRowAt indexPath: IndexPath) -> IndexPath?
在一個(gè)對(duì)象上調(diào)用一個(gè)方法,語(yǔ)法是object.method(parameters)。例如:
// Calling a method on the lists object:
lists.append(checklist)
// Calling a method with more than one parameter:
tableView.insertRows(at: indexPaths, with: .fade)
你可以把調(diào)用方法想象為從一個(gè)對(duì)象向另一個(gè)對(duì)象傳遞消息:“嗨 lists,我從checklist對(duì)象中向你發(fā)送了append的消息。”
你調(diào)用消息所屬的對(duì)象被稱為消息的接收者。
從同一個(gè)對(duì)象中調(diào)用方法非常常見(jiàn),下面的例子中,loadChecklists()調(diào)用了sortChecklists()。它們都是DataModel對(duì)象中的成員:
class DataModel {
fun loadChecklists() {
...
sortChecklists()
}
fun sortChecklists() {
...
}
}
有時(shí)你會(huì)寫為下面這個(gè)樣子:
fun loadChecklists() {
...
self.sortChecklists()
}
關(guān)鍵字self清晰的表明了DataModel對(duì)象自己是這個(gè)消息的接受者。
??:在我們的課程中,調(diào)用方法的時(shí)候,我省略了self關(guān)鍵字,因?yàn)椴⒉皇潜仨氁@樣做。Object-C開(kāi)發(fā)者會(huì)非常樂(lè)意在每個(gè)地方都寫上self,所以你也許會(huì)見(jiàn)到它在Swift中也被大量使用。到底寫與不寫,這是程序員間可以引發(fā)戰(zhàn)爭(zhēng)的一個(gè)話題,但是無(wú)論如何,app并不是太關(guān)心這點(diǎn)。
在一個(gè)方法的內(nèi)部,你也可以使用self關(guān)鍵字來(lái)引用這個(gè)對(duì)象自己:
@IBAction fund cancel() {
delegate?.itemDetailViewControllerDidCancel(self)
}
這里cancel()方法將對(duì)象自身的引用發(fā)送給delegate,所以delegate知道誰(shuí)發(fā)送了這個(gè)itemDetailViewControllerDidCancel()消息。
同時(shí)注意一下這里的可選型鏈接。這個(gè)delegate屬性是個(gè)可選型,所以它可以為nil。在調(diào)用方法前使用一個(gè)問(wèn)號(hào)來(lái)確保delegate為nil時(shí),app不會(huì)掛掉。
方法經(jīng)常會(huì)具有一個(gè)或多個(gè)參數(shù),所以你可以讓它們接收不同數(shù)據(jù)源上的數(shù)據(jù)工作。一個(gè)被限定了數(shù)據(jù)源的方法,可能不會(huì)非常有價(jià)值??纯聪旅娴膕umValuesFormArray()方法,它沒(méi)有參數(shù):
class MyObject {
var numbers = [Int]()
fun sunValuesFromArray() ->Int{
var total = 0
for number in numbers {
total += number
}
return total
}
}
這里,numbers是一個(gè)實(shí)例變量。方法sumValuesFromArray()被這個(gè)實(shí)例變量綁定死了,如果這個(gè)變量不存在,那么這個(gè)方法就沒(méi)用了。
假設(shè)你在這個(gè)app中添加了第二數(shù)組,也想要應(yīng)用上面的計(jì)算,那么其中一個(gè)方法是把這個(gè)方法復(fù)制一遍,重新命名為一個(gè)新的方法來(lái)處理這個(gè)新的數(shù)組。這樣做確實(shí)可行,但是你也從此和聰明絕緣了。
另一個(gè)好一點(diǎn)的選擇是,給這個(gè)方法一個(gè)參數(shù),使得你可以傳送任何你想要計(jì)算的數(shù)組,這樣,這個(gè)方法就從實(shí)例變量中解放出來(lái)了:
func sumValues(from array: [Int])-> Int {
var total = 0
for number in array {
total += number
}
return total
}
現(xiàn)在你可以用任何整數(shù)型的數(shù)組作為它的參數(shù)了。
這并不是說(shuō)方法不應(yīng)該使用實(shí)例變量,只是說(shuō)你想要一個(gè)方法的應(yīng)用更加廣泛,那么給它一個(gè)參數(shù)是個(gè)很好的選擇。
方法的參數(shù)經(jīng)常會(huì)有兩個(gè)名字,一個(gè)外部名稱,一個(gè)內(nèi)部名稱,例如:
fun downloadImage(for searchResult: SearchResult,withTimeout timeout: TimeInterval,andPlaceOn button: UIButton) {
...
}
這個(gè)方法有三個(gè)參數(shù):searchResult,timeout和button。這些是內(nèi)部名稱,你在方法的內(nèi)部用這些名稱來(lái)調(diào)用參數(shù)。
方法的外部名稱是方法名稱的一部分。所以這個(gè)方法的全名是downloadImage(for,withTimeout,andPlaceOn),Swift中的方法名稱經(jīng)常會(huì)特別的長(zhǎng)。
調(diào)用這個(gè)方法的時(shí)候,你需要使用外部名稱:
downloadImage(for:result,withTimeout:10,andPlaceButton)
有時(shí),你會(huì)看到一個(gè)方法它的第一個(gè)參數(shù)沒(méi)有外部名稱,取而代之的是一個(gè)下劃線:
override func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int)-> Int
這種情況經(jīng)常出現(xiàn)在委托方法中,它是Object-C的遺留物,第一個(gè)參數(shù)的內(nèi)部和外部名稱都會(huì)被包含在方法名稱中,比如在Object-C中downloadImage()方法的全名會(huì)是downloadImageForSearchResult。像這樣的命名方式,以后會(huì)非常少見(jiàn)。如果是在Object-C中,這個(gè)方法的名稱會(huì)是tableViewTableVIew,非常古怪是吧,而Swift 中,以下劃線代替外部名稱時(shí),方法名稱中就可以省略這個(gè)參數(shù)的外部名稱,在Swift中,這個(gè)方法的全名是tableView(numberOfRowsInSection)。這樣是不是容易明白多了?Swift在對(duì)方法命名時(shí)更加靈活,但它還是會(huì)保留一些舊的慣例。
在一個(gè)方法的內(nèi)部,你可以做以下事情:
1、創(chuàng)建局部變量或者常量
2、進(jìn)行基本的數(shù)學(xué)運(yùn)算,比如加減乘除
3、將一個(gè)新的值放入變量(局部變量或?qū)嵗兞浚?/p>
4、調(diào)用其他方法
5、使用if或者switch作出判斷
6、用for或者while進(jìn)行循環(huán)處理
7、返回一個(gè)值給調(diào)用者
讓我們來(lái)看看if和for語(yǔ)句的更多細(xì)節(jié)。
作出判斷(Making decisions)
if語(yǔ)句的基本結(jié)構(gòu)是這個(gè)樣子的:
if count == 0 {
text = "No Items"
} else if count == 1 {
text = "1 Item"
} else {
text = "\(count) Items"
}
if后面的表達(dá)式稱之為條件。如果條件為真,那么if后面花括號(hào)內(nèi)的語(yǔ)句會(huì)被執(zhí)行。如果沒(méi)有一個(gè)條件為真,那么最后一個(gè)else后面的花括號(hào)內(nèi)的語(yǔ)句會(huì)被執(zhí)行。
你使用比較運(yùn)算符來(lái)對(duì)兩個(gè)值進(jìn)行比較:
== 等于
!= 不等于
< 小于
<= 小于等于
大于 >
大于等于 >=
使用等于操作時(shí),被比較的兩個(gè)對(duì)象僅在相等時(shí)返回true,比如:
let a = "Hello,world"
let b = "Hello," + "world"
print(a == b) //打印結(jié)果為true
這個(gè)和Object-C有所不同,在Object-C中,必須兩個(gè)對(duì)象是內(nèi)存中的同一個(gè)實(shí)例,才會(huì)返回為true。而Switf中的==操作,僅僅是比較對(duì)象的值,而不管它在內(nèi)存中是不是同一個(gè)對(duì)象,如果在Swift中像做這個(gè)操作的話,需要使用運(yùn)算符 ===,三個(gè)等號(hào)。
你還可以使用邏輯操作符來(lái)連接兩個(gè)表達(dá)式:
&& 與操作,a && b必須在a和b都為true時(shí)才返回true
||或操作符,a || b當(dāng)a,b其中之一為true時(shí),返回true
還有邏輯非操作符!,它的作用是將原本的true轉(zhuǎn)為false,原本的false轉(zhuǎn)為true。(不要和可選型弄混了,邏輯非操作符出現(xiàn)在對(duì)象的前面,而可選型的感嘆號(hào)出現(xiàn)在對(duì)象的后面)
可以使用括號(hào)()來(lái)對(duì)表達(dá)式分組:
if ((this && that) || (such && so)) && !other {
...
}
它讀作:
if ((this and that) or (such and so)) and not other {
...
}
為了看起來(lái)更加清晰一些,我們寫的有層次一點(diǎn):
if (
(this and that)
or
(such and so)
)
and
(not other)
當(dāng)然,你弄的越復(fù)雜,越難記清楚自己在做什么!
Swift中還有一種非常強(qiáng)大的結(jié)構(gòu),可以用來(lái)做出判斷,那就是switch語(yǔ)句:
switch condition {
case value1:
//語(yǔ)句
case value2:
//語(yǔ)句
case value3:
//語(yǔ)句
default:
//語(yǔ)句
它的效果和多個(gè)if else的效果是一致的,上面的代碼等同于:
if condition == value1 {
//語(yǔ)句
} else if condition == value2 {
//語(yǔ)句
}else if condition == value3 {
//語(yǔ)句
} else {
//語(yǔ)句
}
相較之下,switch在這種情況中更加便利,而且意思清晰。而且Swift版的switc比Object-C版的更加強(qiáng)大。例如,你可以使用區(qū)間范圍:
switch difference {
case 0:
title = "Perfect!"
case 1..<5:
title = "You almost had it!"
case 5..<10:
title = "Pretty good!"
default:
title = "Not even close..."
這里的..<是半開(kāi)區(qū)間操作符。它可以創(chuàng)建兩個(gè)值之間的區(qū)間,其中的值都是不重復(fù)的,半開(kāi)區(qū)間1..<5等價(jià)于閉區(qū)間1...4。
你會(huì)在后面的課程中見(jiàn)到switch語(yǔ)句的實(shí)際用例。
注意一下,if語(yǔ)句中的reture會(huì)比方法中的returen更早的返回:
fun divide(_ a: Int, by b: Int) ->Int {
if b == 0 {
print("不能除以0")
return 0
}
return a / b
}
對(duì)于沒(méi)有返回值的方法而言,if中的return甚至可以結(jié)束掉方法:
fun performDifficultCalculation(list: [Double]) {
if list.count < 2 {
print("樣本過(guò)少")
return
}
//這里執(zhí)行復(fù)雜的運(yùn)算
}
在這個(gè)例子中,return的意思就是“我們退出方法吧”。任何return后面的語(yǔ)句都會(huì)被忽略掉。
你也可以把上面的方法寫成下面這個(gè)樣子:
fun performDifficultCalculation(list: [Double]) {
if list.count < 2 {
print("樣本過(guò)少")
} else {
//這里執(zhí)行復(fù)雜的運(yùn)算
}
}
像這種只有兩種可能的情況下,上面兩個(gè)方法的作用一樣,使用哪個(gè)都可以,我個(gè)人比較喜歡第二種。
有時(shí)你會(huì)看到下面這個(gè)樣子的代碼:
fun someMethod() {
if condition1 {
if condition2 {
if condition3 {
//語(yǔ)句
} else {
//語(yǔ)句
}
} else {
//語(yǔ)句
} else {
//語(yǔ)句
}
}
這種代碼非常難讀,我喜歡將它們重構(gòu)為下面這個(gè)樣子:
fun someMethod() {
if !condition1 {
//語(yǔ)句
}
if !condition2 {
//語(yǔ)句
}
if !condition3 {
//語(yǔ)句
}
//語(yǔ)句
}
這兩段代碼的作用其實(shí)是一樣的,但是后一種更加容易理解。(注意一下,第二種寫法中使用了!邏輯非來(lái)轉(zhuǎn)換了表達(dá)式的意思)
Swift中有一種特殊的語(yǔ)句,guard來(lái)幫助你處理這種復(fù)雜的情況,用guard重寫一下上面的方法就是:
fun someMethod() {
guard condition1 else {
//語(yǔ)句
return
}
guard condition21 else {
//語(yǔ)句
return
}
...
你要自己嘗試這些方法,比較看看哪種可讀性最好,哪種看起來(lái)最好,這樣慢慢的你就會(huì)很有經(jīng)驗(yàn)了。
循環(huán)(Loops)
你之前已經(jīng)見(jiàn)識(shí)過(guò)了,如何用for in來(lái)歷遍一個(gè)數(shù)組:
for item in items {
if !item.checked {
count += 1
}
}
也可以寫作:
for item in items where !item.checked {
count += 1
}
for in中的語(yǔ)句會(huì)對(duì)每個(gè)items數(shù)組中的對(duì)象執(zhí)行一遍。
注意一下,變量item的僅在for語(yǔ)句中有效,你不能在外面引用它,它的生命期比局部變量還要短。
有些語(yǔ)言,也包括Swift 2,中的for語(yǔ)句是這個(gè)樣子的:
for var i = 0;i<5;++i {
print(i)
}
當(dāng)你運(yùn)行這個(gè)代碼,會(huì)得到如下結(jié)果:
0
1
2
3
4
然而,在Swift 3種,這種for循環(huán)已經(jīng)被拋棄了,取而代之的是,你可以直接使用區(qū)間范圍,就像下面這樣:
for i in 0 ... 4 {
print(i)
}
順便說(shuō)一下,也可寫作:
for i in stride(from: 0,to: 5,by: 1) {
print(i)
}
stride函數(shù)創(chuàng)建了一個(gè)專門的對(duì)象來(lái)代表從1到5,每次增加1。如果你只想要偶數(shù),你可以把by參數(shù)改為2。如果你給by參數(shù)一個(gè)負(fù)數(shù)的話,那么stride就可以實(shí)現(xiàn)倒著數(shù)的功能。
for語(yǔ)句并不是唯一的執(zhí)行循環(huán)的語(yǔ)句,另一個(gè)非常強(qiáng)大的循環(huán)結(jié)構(gòu)就是while語(yǔ)句:
while something is true {
//語(yǔ)句
}
while語(yǔ)句會(huì)一直保持循環(huán),知道條件為false為止。還可以使用下面這種形式:
repeat {
//語(yǔ)句
} while something is true
在這種情況中,條件是在語(yǔ)句執(zhí)行后才判斷的,所以括號(hào)內(nèi)的語(yǔ)句至少也會(huì)被執(zhí)行一次。
你可以使用while語(yǔ)句重寫一下循環(huán)Checklists中的對(duì)象:
var count = 0
var i = 0
while i < items.count {
let item = items[i]
if !item.checked {
count += 1
}
i += 1
}
這些循環(huán)結(jié)構(gòu)的作用大致相同,只是看起來(lái)有些不一樣。每一種都可以使你重復(fù)執(zhí)行一段語(yǔ)句,直到條件不符合為止。
然而,使用while會(huì)比f(wàn)or in要看起來(lái)復(fù)雜一些,所以大多數(shù)時(shí)候,我們都會(huì)使用for in。
使用for in、while、repeat并沒(méi)有什么不同,只是可讀性上有所區(qū)別。
??:上面例子中的item.count和count是兩種不同的東西,只是名字一樣。item.count中的count是數(shù)組items中的屬性用于返回?cái)?shù)組中元素的個(gè)數(shù);后面的一個(gè)count是一個(gè)局部變量,用于對(duì)沒(méi)有激活對(duì)勾符號(hào)的item對(duì)象計(jì)數(shù)。
就你可以在方法中使用return退出方法一樣,你可以使用break來(lái)提前退出循環(huán):
var found = false
for item in array {
if item == searchText {
found = true
break
}
}
這個(gè)例子中,for語(yǔ)句在數(shù)組中循環(huán),直到找到第一個(gè)與searchText的值相當(dāng)?shù)闹岛?,將found設(shè)置為true,然后退出循環(huán),不再查看數(shù)組中剩下的對(duì)象。因?yàn)槟阋呀?jīng)找到了你想要的東西,所以沒(méi)有必要把整個(gè)數(shù)組都循環(huán)完畢。
還存在一個(gè)contiue語(yǔ)句,和break的作用正好相反。它的作用是立即跳到下一個(gè)迭代中,當(dāng)你使用contiue時(shí),你的意思就是“目前這個(gè)item已經(jīng)結(jié)束了,我們?nèi)タ纯聪乱粋€(gè)吧!”
在函數(shù)編程中,循環(huán)經(jīng)常會(huì)被map,filter或者reduce替代。它們是一些操作集合的函數(shù),對(duì)集合中每一個(gè)元素執(zhí)行一段代碼,并且返回一個(gè)新的集合作為結(jié)果。
例如,在數(shù)組上使用filter,會(huì)保留符合某些條件的元素。比如要得到未激活對(duì)勾符號(hào)的ChecklistItem對(duì)象,你可以這樣寫:
var uncheckedItems = items.filter { item in !item.checked}
這樣寫比循環(huán)看起來(lái)要簡(jiǎn)單多了。函數(shù)編程是一個(gè)非常大的話題,所以在這里我們不會(huì)展開(kāi)太多。
對(duì)象(Objects)
將功能和數(shù)據(jù)結(jié)合在一起的可重用單元,都是對(duì)象。
數(shù)據(jù)是由對(duì)象中的實(shí)例變量和實(shí)例常量組成。我們經(jīng)常以對(duì)象的屬性形式引用它們。功能由對(duì)象的方法提供。
在你的Swift程序中,你使用過(guò)已存在的對(duì)象,比如String,Array,Date,UITableView,以及你自己創(chuàng)建的對(duì)象。
定義一個(gè)新的對(duì)象,你需要一個(gè)新的Swift文件,比如MyObject.swift,并且包含一個(gè)類(class)。比如:
class MyObject {
var text: String
var count = 0
let maximum = 100
init() {
text = "Hello World"
}
fun doSomething() {
//語(yǔ)句
}
}
在class的花括號(hào)內(nèi),你添加了屬性(實(shí)例變量和實(shí)例常量)和方法。
屬性有兩種類型:
1、存儲(chǔ)屬性,它們通常是實(shí)例變量和實(shí)例常量。
2、計(jì)算屬性,不存儲(chǔ)東西,而是執(zhí)行某些邏輯
下面是一個(gè)關(guān)于計(jì)算屬性的例子:
var indexOfSelectedChecklist: Int {
get {
return UserDefaults.standard().integerForKey("ChecklistIndex")
}
set {
UserDefaults.standard().set(newValue,forKey: "ChecklistIndex")
}
}
indexOfSelectedChecklist屬性并不存儲(chǔ)一個(gè)值,取而代之的是,每次有人使用這個(gè)屬性時(shí),它執(zhí)行g(shù)et或者set內(nèi)的代碼。另一個(gè)選擇是,分別寫一個(gè)setIndexOfSelectedChecklist()和getIndexOfSelectedChecklist()方法,但是這樣讀起來(lái)不是很好。
關(guān)鍵字@IBOutlet的意思是,這個(gè)屬性可以被界面建造器中的用戶接口元素引用,比如label和button。這種屬性通常都被聲明為weak和可選型。類似的,@IBAction關(guān)鍵字被用于和用戶交互時(shí)被觸發(fā)的方法。
這里有三種類型的方法:
1、實(shí)例方法
2、類方法
3、init方法
你已經(jīng)知道了方法就是屬于某一個(gè)對(duì)象的函數(shù)。調(diào)用這種類型的方法你首先需要一個(gè)這個(gè)對(duì)象的實(shí)例:
let myInstance = MyObject() //創(chuàng)建一個(gè)對(duì)象的實(shí)例
myInstance.doSomething() //調(diào)用方法
你也可以創(chuàng)建一個(gè)類方法,這樣就可以在沒(méi)有實(shí)例的情況下使用這個(gè)方法。事實(shí)上,類方法經(jīng)常被當(dāng)作“工廠”方法使用,用來(lái)創(chuàng)建新的實(shí)例:
class MyObject {
...
class fun makeObject(text: String)-> MyObject {
let m = MyObject()
m.text = text
return m
}
}
let MyInstance = MyObject.makeObject(text: "Hello world")
init方法,或者叫做初始化設(shè)置,在創(chuàng)建一個(gè)新的對(duì)象實(shí)例的過(guò)程中被使用。你也可以使用init方法來(lái)取代上面的那個(gè)工廠方法:
class MyObject {
...
init(text: String) {
self.text = text
}
}
init方法的主要目的是將對(duì)象中的實(shí)例變量填滿。任何沒(méi)有值的實(shí)例變量和實(shí)例常量都必須在init方法中被給予一個(gè)值。
Swift不允許變量或者常量沒(méi)有值(可選型例外),并且init方法是你給變量或者常量賦值的最后一次機(jī)會(huì)。
對(duì)象可以擁有一個(gè)以上的init方法;具體使用哪一個(gè)要依據(jù)具體情況而定。
例如,一個(gè)UITableViewController,從故事模版中自動(dòng)被讀取時(shí),使用init?(coder)初始化,手工從nib文件中讀取時(shí),使用init(nibName,bundle)初始化,或者沒(méi)有從故事模版和nib文件中構(gòu)造時(shí),使用init(style)初始化。有時(shí)你會(huì)用到這個(gè),而有時(shí)你會(huì)用到那個(gè)。
當(dāng)對(duì)象不再被使用時(shí),你可以提供一個(gè)deinit方法。在對(duì)象被破壞掉前調(diào)用它。
順便說(shuō)一下,class并不是Swift中唯一定義對(duì)象的方法。還存在其他類型的對(duì)象,比如structs和enums。你會(huì)在后面學(xué)到這些,所以在這里,我們就點(diǎn)到為止了。
協(xié)議(Protocols)
一個(gè)協(xié)議就是一組方法名稱的列表:
protocol MyProtocol {
func someMethod(value: Int)
func anotherMethod()-> String
}
協(xié)議就類似于工作列表。它列出了你的公司中每個(gè)具體職位的工作。
但是列表自己本身并不工作,它僅僅是打印出來(lái)給大家看的東西。所以你需要雇傭具體的員工來(lái)完成列表上的工作。而這些員工,就是具體的對(duì)象。
對(duì)象需要被指明自己需要遵守的協(xié)議:
class MyObject: MyProtocol {
...
}
這樣,這個(gè)對(duì)象就需要完成協(xié)議中列出的所有方法。(否則,就炒了它)
此時(shí),你就可以引用這個(gè)對(duì)象,同時(shí)還有協(xié)議:
var m1: MyObject = MyObject()
var m2: MyProtocol = MyObject()
對(duì)于代碼中任何使用m2變量的部分,它是否是MyObject對(duì)象并不重要。m2類型是MyProtocol,不是MyObject。
所有你的代碼看到的是,m2是某個(gè)遵守MyProtocol協(xié)議的對(duì)象,但是具體是什么樣的對(duì)象并不重要。
換而言之,你并不關(guān)心你雇用的員工,是不是兼職其他工作,只要他和你需要的東西不沖突,你就可以雇傭他。
我們已經(jīng)快速的回顧了一遍你所遇到的Swift語(yǔ)法知識(shí)。在結(jié)束了這些理論之后,是時(shí)候開(kāi)始我們的app開(kāi)發(fā)了。