一.Swift中的函數(shù)
1.函數(shù)的定義與使用
在介紹Swift中的函數(shù)之前,我想用Objective-C中的一個(gè)簡(jiǎn)單的加法函數(shù)來(lái)作為引子大猛,然后類比著實(shí)現(xiàn)一下Swift中相同功能的函數(shù)历涝。關(guān)于函數(shù)定義就比較簡(jiǎn)單了诅需,就是一些語(yǔ)法的東西,下面的代碼片段是Objc中求兩個(gè)整數(shù)之和的函數(shù)荧库,并返回兩個(gè)數(shù)的和堰塌。
- (NSInteger)sumNumber1:(NSInteger) number1
number2:(NSInteger) number2 { return number1 + number2;
}
函數(shù)的功能比較簡(jiǎn)單了,就是把兩個(gè)整數(shù)傳進(jìn)來(lái)分衫,然后返回兩個(gè)整數(shù)的和场刑。接下來(lái)將用Swift語(yǔ)言實(shí)現(xiàn),也好通過(guò)這個(gè)實(shí)例來(lái)熟悉一下Swift語(yǔ)言中定義函數(shù)的語(yǔ)法蚪战。下方是Swift語(yǔ)言中求兩個(gè)整數(shù)之和的函數(shù)牵现。語(yǔ)法比較簡(jiǎn)單了,在Swift中定義函數(shù)邀桑,我們會(huì)使用到關(guān)鍵字func來(lái)聲明函數(shù)瞎疼。
//函數(shù)定義
func sum (number1:Int, number2:Int) -> Int{
return number1 + number2;
}
用文字來(lái)描述Swift定義基本函數(shù)的語(yǔ)法就是: func 函數(shù)名 (形參列表) -> 返回值類型 { 函數(shù)體},這樣你就可以定義一個(gè)函數(shù)了壁畸。當(dāng)然贼急,函數(shù)定義時(shí)還有好多其他的用法茅茂,下面會(huì)詳細(xì)介紹。上面函數(shù)的調(diào)用方法如下:
let sumTwoNubmer = sum(2, number2: 3);
2.函數(shù)中的形參列表
(1) 默認(rèn)的形參是常量(let)
在函數(shù)的形參列表中太抓,默認(rèn)的形參是常量空闲。也就是相當(dāng)于用let關(guān)鍵字對(duì)形參進(jìn)行修飾了。我們可以做個(gè)試驗(yàn)走敌,把上面加法函數(shù)做一個(gè)修改碴倾,在加法函數(shù)中對(duì)number1進(jìn)行加1操作,你會(huì)得到一個(gè)錯(cuò)誤掉丽,這個(gè)錯(cuò)誤的大體意思就是“number1是不可被修改的跌榔,因?yàn)樗莑et類型的常量”。并且編譯器還給人出了Fix-it(修復(fù))的方案机打,就是在number1前面使用var關(guān)鍵字進(jìn)行修飾矫户,使其成為變量,這樣才可以修改其值残邀。
上面說(shuō)這么多皆辽,一句話:形參默認(rèn)是常量,如果你想讓其是變量芥挣,那么你可以使用var關(guān)鍵字進(jìn)行修飾驱闷,這樣被關(guān)鍵字var修飾的變量在函數(shù)中就可以被修改。下方就是報(bào)的這個(gè)錯(cuò)誤空免,和編譯器提供的解決方案空另。(在Objc中默認(rèn)可以在函數(shù)中改變形參的值)
(2)給形參命名
為了代碼的可讀性和可維護(hù)性,我們?cè)诙x函數(shù)時(shí)蹋砚,需要為每個(gè)參數(shù)名一個(gè)名字扼菠,這樣調(diào)用者見名知意,很容易就知道這個(gè)參數(shù)代表什么意思了坝咐。接下來(lái)還是在上述加法函數(shù)中進(jìn)行修改循榆,為每個(gè)參數(shù)名一個(gè)名字,并看一下調(diào)用方式墨坚。修改上面的函數(shù)秧饮,給第一個(gè)形參命名成numberOne, 第二個(gè)形參為numberTwo, 下方是修改后的函數(shù)。 緊接著sum()函數(shù)的調(diào)用方式也會(huì)有所改變泽篮,在調(diào)用函數(shù)時(shí)編譯器會(huì)給出參數(shù)的名稱盗尸,這樣調(diào)用者一目了然。
//函數(shù)定義
func sum (numberOne number1:Int, numberTwo number2:Int) -> Int{
return number1 + number2;
}
let sumTwoNubmer = sum(numberOne: 10, numberTwo: 20);
調(diào)用上述函數(shù)時(shí)帽撑,下方是編譯器給出的提示泼各,一目了然呢。
關(guān)于Swift中參數(shù)名的內(nèi)容亏拉,要說(shuō)明的是在Swift1.0的時(shí)候扣蜻,你可以在參數(shù)前面添加上#號(hào)寸癌,然后參數(shù)名就與變量(或者常量)的名字相同,而Swift2.0后這個(gè)東西去掉了弱贼,因?yàn)槟J(rèn)就相當(dāng)于Swift1.0中添加#號(hào)。
(3) 函數(shù)的傳參與傳引用
先暫且這么說(shuō)著磷蛹,在C語(yǔ)言的函數(shù)中可以給函數(shù)傳入?yún)?shù)吮旅,或者傳入實(shí)參的內(nèi)存地址就是所謂的傳引用。如果傳入的是引用的話味咳,在函數(shù)中對(duì)值進(jìn)行修改的話庇勃,那么出了函數(shù),這個(gè)被修改的值是可以被保留的槽驶。在Swift中也是可以的责嚷,不過(guò)你需要使用inout關(guān)鍵字修飾形參,并且在使用該函數(shù)時(shí)掂铐,用&來(lái)修飾罕拂。這一點(diǎn)和C語(yǔ)言中類似,&就是取地址符全陨。下方是inout使用的一個(gè)小實(shí)例爆班。
func incrementStepTwo (inout myNumber:Int) {
myNumber += 2
}
var myTestNumber = 6
incrementStepTow(&myTestNumber) //myTestNumber = 8
myTestNumber變量經(jīng)過(guò)incrementStepTwo()函數(shù)后,其值就會(huì)增加2辱姨。當(dāng)然前提是myTestNumber是變量柿菩,如果myTestNumber是常量的話,那么對(duì)不起雨涛,調(diào)用該函數(shù)就會(huì)報(bào)錯(cuò)枢舶,下面是把var改成let后IDE給的錯(cuò)誤提示。錯(cuò)誤原因很顯然是你動(dòng)了一個(gè)不該動(dòng)的值替久,也就是常量不可再次被修改的凉泄。
(4) 不定參數(shù)函數(shù)
不定參數(shù)函數(shù)也就是形參的個(gè)數(shù)是不定的,但是形參的類型必須是相同的侣肄。不定形參在使用時(shí)怎么取呢旧困?不定個(gè)數(shù)的形參實(shí)際上是一個(gè)數(shù)組,我們可以通過(guò)for循環(huán)的形式來(lái)遍歷出每個(gè)形參的值稼锅,然后使用就可以了吼具。下方incrementMultableAdd()函數(shù)的形參的個(gè)數(shù)是不定的,其功能是求多個(gè)整數(shù)的和矩距。在函數(shù)中我們只需遍歷每個(gè)參數(shù)拗盒,然后把每個(gè)參數(shù)進(jìn)行相加,最后返回所求的和即可锥债。函數(shù)比較簡(jiǎn)單陡蝇,再此就不在啰嗦了痊臭。
(5) 默認(rèn)形參值
在Swift語(yǔ)言中是支持給形參賦初始值的,這一點(diǎn)在其他一些編程語(yǔ)言中也是支持的登夫。但是Objective-C這么看似古老的語(yǔ)言中就不支持給形參指定初始值广匙,在Swift這門現(xiàn)代編程語(yǔ)言中是支持這一特性的。默認(rèn)參數(shù)要從參數(shù)列表后開始為參數(shù)指定默認(rèn)值恼策,不然就會(huì)報(bào)錯(cuò)鸦致。下方就是為函數(shù)的形參指定默認(rèn)參數(shù)的示例。一個(gè)表白的方法sayLove(), 形參youName默認(rèn)是“山伯”涣楷, 形參loverName默認(rèn)是“英臺(tái)”分唾。 緊接著是sayLove函數(shù)的三種不同的調(diào)用方式,在調(diào)用函數(shù)時(shí)你可以不傳參數(shù)狮斗,可以傳一個(gè)參數(shù)绽乔,當(dāng)然傳兩個(gè)也是沒(méi)問(wèn)題的。
因?yàn)楹瘮?shù)的每個(gè)參數(shù)都是有名字的碳褒,在含有默認(rèn)參數(shù)的函數(shù)調(diào)用時(shí)折砸,可以給任意一個(gè)參數(shù)進(jìn)行傳值,其他參數(shù)取默認(rèn)值沙峻,這也是Swift的一大特色之一鞍爱,具體請(qǐng)看如下簡(jiǎn)單的代碼示例:
3.函數(shù)類型
每個(gè)函數(shù)都有自己的所屬類型,函數(shù)類型說(shuō)白了就是如果兩個(gè)函數(shù)參數(shù)列表相同以及返回值類型相同专酗,那么這兩個(gè)函數(shù)就有著相同的函數(shù)類型睹逃。在Swift中可以定義一個(gè)變量或者常量來(lái)存儲(chǔ)一個(gè)函數(shù)的類型。接下來(lái)將用過(guò)一個(gè)實(shí)例還介紹一下函數(shù)類型是個(gè)什么東西祷肯。
(1) 首先創(chuàng)建兩個(gè)函數(shù)類型相同的函數(shù)沉填,一個(gè)函數(shù)返回兩個(gè)整數(shù)的差值,另一個(gè)函數(shù)返回兩個(gè)整數(shù)的乘積佑笋。當(dāng)然這兩個(gè)函數(shù)比較簡(jiǎn)單翼闹,直接上代碼:
//現(xiàn)定義兩個(gè)函數(shù)類型相同的函數(shù)
func diff (number1:Int, number2:Int) -> Int {
return number1 - number2;
}
func mul (number1:Int, number2:Int) -> Int {
return number1 * number2;
}
(2) 函數(shù)定義好后,接著要定義個(gè)一個(gè)枚舉來(lái)枚舉每種函數(shù)的類型蒋纬,下面定義這個(gè)枚舉在選擇函數(shù)時(shí)會(huì)用到猎荠,枚舉定義如下:
//定義兩種計(jì)算的枚舉類型
enum CountType:Int {
case DiffCount = 0
case MulCount
}
(3) 接下來(lái)就是把(1)和(2)中定義的東西通過(guò)一個(gè)函數(shù)來(lái)組合起來(lái)。說(shuō)白了蜀备,就是定義個(gè)函數(shù)來(lái)通過(guò)枚舉值返回這個(gè)枚舉值所對(duì)應(yīng)的函數(shù)類型关摇。有時(shí)候說(shuō)多了容易犯迷糊,就直接上代碼得了碾阁。下方函數(shù)的功能就是根據(jù)傳進(jìn)來(lái)的枚舉值來(lái)返回相應(yīng)的函數(shù)類型输虱。
//選擇類型的函數(shù),并返回相應(yīng)的函數(shù)類型
func choiseCountType(countType:CountType) -> ((Int, Int) -> Int) {
//函數(shù)類型變量
var myFuncType:(Int, Int) -> Int
switch countType {
case .DiffCount:
myFuncType = diff
case .MulCount:
myFuncType = mul
}
return myFuncType;
}
(4) 接下來(lái)就是使用(3)中定義的函數(shù)了脂凶,首先我們需要定義一個(gè)相應(yīng)函數(shù)類型((Int, Int) -> Int)的變量來(lái)接收choiseCountType()函數(shù)中返回的函數(shù)類型宪睹,然后調(diào)用該函數(shù)類型變量愁茁,在Playground中執(zhí)行的結(jié)果如下:
4.函數(shù)嵌套
我們可以把 3 中的代碼使用函數(shù)嵌套進(jìn)行重寫,在Swift中是支持函數(shù)嵌套的亭病。 所以可以吧3.1和3.2中的函數(shù)放到3.3函數(shù)中的鹅很,所以我們可以對(duì)上述代碼使用函數(shù)嵌套進(jìn)行重寫。使用函數(shù)嵌套重寫后的代碼如下所示罪帖,當(dāng)然道宅,choiseCountType()函數(shù)的調(diào)用方式?jīng)]用發(fā)生改變,重寫后的調(diào)用方式和3.4中的調(diào)用方式是一樣一樣的胸蛛。
//選擇類型的函數(shù),并返回相應(yīng)的函數(shù)類型
func choiseCountType(countType:CountType) -> ((Int, Int) -> Int) {
//現(xiàn)定義兩個(gè)函數(shù)類型相同的函數(shù)
func diff (number1:Int, number2:Int) -> Int {
return number1 - number2;
}
func mul (number1:Int, number2:Int) -> Int {
return number1 * number2;
}
//函數(shù)類型變量
var myFuncType:(Int, Int) -> Int
switch countType {
case .DiffCount:
myFuncType = diff
case .MulCount:
myFuncType = mul
}
return myFuncType;
}
二. 閉包
說(shuō)道Swift中的閉包呢樱报,不得不提的就是Objective-C中的Block, 其實(shí)兩者是一個(gè)東西葬项,使用方式以及使用場(chǎng)景都是相同的。我們完全可以類比著Objective-C中的Block來(lái)介紹一下Swift中的Closure(閉包)迹蛤。其實(shí)就是匿名函數(shù)民珍。接下來(lái)的這段內(nèi)容,先介紹一下Swift中Closure的基本語(yǔ)法盗飒,然后在類比著ObjC中的Block窺探一下Closure的使用場(chǎng)景嚷量。
1.Closure變量的聲明
Closure就是匿名函數(shù),我們可以定義一個(gè)閉包變量逆趣,而這個(gè)閉包變量的類型就是我們上面介紹的“函數(shù)類型”蝶溶。定義一個(gè)閉包變量其實(shí)就是定義一個(gè)特定函數(shù)類型的變量,方式如下宣渗。因?yàn)镃losure變量沒(méi)有賦初始值抖所,所以我們把其聲明為可選類型的變量。在使用時(shí)痕囱,用!強(qiáng)制打開即可田轧。
var myCloure0:((Int, Int) -> Int)?
除了上面的方式外,我們還用另一種常用的聲明閉包變量的方式鞍恢。那就是使用關(guān)鍵字typealias定義一個(gè)特定函數(shù)類型傻粘,我們就可以拿著這個(gè)類型去聲明一個(gè)Closure變量了,如下所示
//定義閉包類型 (就是一個(gè)函數(shù)類型)
typealias MyClosureType = (Int, Int) -> Int
var myCloure:MyClosureType?
2.給Closure變量賦值
給Closure變量賦值帮掉,其實(shí)就是把一個(gè)函數(shù)體賦值給一個(gè)函數(shù)類型的變量弦悉,和函數(shù)的定義區(qū)別不大。但是給閉包變量賦值的函數(shù)體中含有參數(shù)列表蟆炊,并且參數(shù)列表和真正的函數(shù)體之間使用關(guān)鍵字in來(lái)分割警绩。 閉包可選變量的調(diào)用方式與普通函數(shù)沒(méi)什么兩樣,唯一不同的是這個(gè)函數(shù)需要用!來(lái)強(qiáng)制打開才可以使用盅称。賦值和調(diào)用方式如下肩祥。
3.數(shù)組中常用的閉包函數(shù)
在Swift的數(shù)組中自帶了一些比較好用的閉包函數(shù)后室,例如Map, Filter, Reduce。接下來(lái)就好好的看一下這些閉包混狠,用起來(lái)還是比較爽的岸霹。
(1) Map(映射)
說(shuō)到Map的用法和功能,不能不說(shuō)的是如果你使用過(guò)ReactiveCocoa框架将饺,那么對(duì)里邊的Sequence中的Map的使用方式并不陌生贡避。其實(shí)兩者的使用方法和功能是極為相似的。如果你沒(méi)使用過(guò)RAC中的Map予弧,那也無(wú)關(guān)緊要刮吧,接下來(lái)我們先上段代碼開看一下數(shù)組中的Map閉包函數(shù)。
通過(guò)上面的代碼段以及運(yùn)行結(jié)果掖蛤,我們不難看出杀捻,map閉包函數(shù)的功能就是對(duì)數(shù)組中的每一項(xiàng)進(jìn)行遍歷,然后通過(guò)映射規(guī)則對(duì)數(shù)組中的每一項(xiàng)進(jìn)行處理蚓庭,最終的返回結(jié)果是處理后的數(shù)組(以一個(gè)新的數(shù)組形式出現(xiàn))致讥。當(dāng)然,原來(lái)數(shù)組中的元素值是保持不變的器赞,這就是map閉包函數(shù)的用法與功能垢袱。
(2) Filter (過(guò)濾器)
Filter的用法還是比較好理解的,F(xiàn)ilter就是一個(gè)漏勺港柜,就是用來(lái)過(guò)濾符合條件的數(shù)據(jù)的请契。在ReactiveCocoa中的Sequence也是有Filter的,用法還是來(lái)過(guò)濾Sequence中的數(shù)據(jù)的夏醉。而在數(shù)組中的Filter用來(lái)過(guò)濾數(shù)組中的數(shù)據(jù)姚糊,并且返回新的數(shù)組,新的數(shù)組中存放的就是符合條件的數(shù)據(jù)授舟。Filter的用法如下實(shí)例救恨,下方的實(shí)例就是一個(gè)身高的過(guò)濾,過(guò)濾掉身高小于173的人释树,返回大于等于173的身高數(shù)據(jù)肠槽。
(3)Reduce
在ReactiveCocoa中也是有Reduce這個(gè)概念的,ReactiveCocoa中使用Reduce來(lái)合并消減信號(hào)量奢啥。在swift的數(shù)組中使用Reduce閉包函數(shù)來(lái)合并items, 并且合并后的Value秸仙。下方的實(shí)例是一個(gè)Salary的數(shù)組,其中存放的是每個(gè)月的薪水桩盲。我們要使用Reduce閉包函數(shù)來(lái)計(jì)算總的薪水寂纪。下方是DEMO的截圖: