我的博客地址: fengqiangboy.com
文檔更新說明:
? 2016年10月12日 v1.0 初稿
? 2016年10月13日 v2.0 增加閉包部分
1、函數(shù)
1.1、函數(shù)的定義和調(diào)用
- 使用
func
關(guān)鍵字來定義一個函數(shù) - 在swift中,大概我們也可以自豪的說"一切皆對象"了诫睬,函數(shù)也可以當(dāng)做一個特殊的對象來看待没炒。
// 定義一個不帶參數(shù)的函數(shù)
func sendMessage() {
let message = "Hey there!"
print(message)
}
// 調(diào)用不帶參數(shù)的函數(shù)
sendMessage()
/**
輸出結(jié)果:
Hey there!
*/
1.2、帶參數(shù)的函數(shù)
- 定義帶參數(shù)的函數(shù)糜工,只需要在定義的時候颂斜,括號內(nèi)填入相應(yīng)的參數(shù)为迈,默認(rèn)情況下敌蜂,是用
let
聲明的常量 - 在下面的定義中感论,
func
代表定義一個函數(shù),是個關(guān)鍵字紊册,sendMessage
是這個函數(shù)的名字比肄,shouting
是參數(shù)的名字,可在函數(shù)內(nèi)部使用囊陡,在調(diào)用的時候需要聲明寫出來Bool
代表參數(shù)類型芳绩,這里是一個布爾類型
// 定義一個帶參數(shù)的函數(shù)
func sendMessage(shouting: Bool) {
var message = "Hey there!"
if shouting {
message = message.uppercased()
}
print(message)
}
// 調(diào)用一個帶參數(shù)的函數(shù)
sendMessage(shouting: true)
/**
輸出結(jié)果:
HEY THERE!
*/
1.3、函數(shù)的參數(shù)標(biāo)簽
- swift中撞反,為了使函數(shù)在調(diào)用和定義的時候都能見名知意妥色,提供了兩個命名(參數(shù)標(biāo)簽和參數(shù)名),中間以空格分開
- 參數(shù)名是給調(diào)用的時候函數(shù)內(nèi)部使用的遏片,參數(shù)標(biāo)簽是調(diào)用函數(shù)的時候嘹害,當(dāng)做函數(shù)名來用的
- 實際使用中,合理運用這兩個參數(shù)吮便,可以大大提高代碼的可讀性
- 一個函數(shù)中笔呀,多個參數(shù)名不能重名,但是參數(shù)標(biāo)簽可以重名(建議不要那么無聊去寫重名的)
- 下面函數(shù)中“
to
”就是函數(shù)標(biāo)簽髓需,recipient
和shouting
是參數(shù)名 - 不想在調(diào)用的時候?qū)懗鰠?shù)標(biāo)簽许师,可以在定義函數(shù)的時候使用“
_
”來代替參數(shù)標(biāo)簽,(1.4)
func sendMessage(to recipient: String, shouting: Bool) {
var message = "Hey there, \(recipient)!"
if shouting {
message = message.uppercased()
}
print(message)
}
sendMessage(to: "Morgan", shouting: false)
/**
輸出結(jié)果:
Hey there, Morgan!
*/
1.4僚匆、省略參數(shù)標(biāo)簽
- 有些參數(shù)名可能會跟函數(shù)名重名微渠,比如下面這個函數(shù),兩個message咧擂,在調(diào)用的時候就會顯得特別奇怪逞盆,這時,可以用"
_
"來代替參數(shù)名字松申,調(diào)用的時候看起來就更加舒服了
// 名字優(yōu)化之前
func sendMessage(message: String, to recipient: String, shouting: Bool)
// 省略參數(shù)名字之后
func sendMessage(_ message: String, to recipient: String, shouting: Bool) {
var message = "\(message), \(recipient)!"
if shouting {
message = message.uppercased()
}
print(message)
}
// 調(diào)用的時候可以省略參數(shù)名字
sendMessage("See you at the Bash", to: "Morgan", shouting: false)
/**
輸出結(jié)果:
See you at the Bash, Morgan!
*/
1.5云芦、參數(shù)的默認(rèn)值
- 在上面的函數(shù)中,其實最后那個參數(shù)我們一般都是傳false攻臀,這時焕数,調(diào)用的時候再每次都寫這個參數(shù)就顯得多余了
- swift中提供了一個默認(rèn)參數(shù)纱昧,即可以給函數(shù)的參數(shù)一個默認(rèn)值刨啸,調(diào)用的時候不傳就使用默認(rèn)值
- 建議把帶默認(rèn)值的參數(shù)寫在后面,否則识脆,你會回來點贊的(調(diào)用的時候參數(shù)順序看得清晰些)
- 默認(rèn)參數(shù)在定義函數(shù)的時候?qū)懺陬愋秃竺嫔枇缦拢?/li>
// 參數(shù)帶有默認(rèn)值的函數(shù)
func sendMessage(_ message: String, to recipient: String, shouting: Bool = false) {
var message = "\(message), \(recipient)!"
if shouting {
message = message.uppercased()
}
print(message)
}
// 調(diào)用帶有默認(rèn)值的函數(shù)
sendMessage("See you at the Bash", to: "Morgan")
/**
輸出結(jié)果:
See you at the Bash, Morgan!
*/
1.6善已、可變參數(shù)
- 可變參數(shù)指的是:這個參數(shù)可以傳入0個,也可以傳入10000個离例,就像OC里面的
NSLog()
函數(shù)一樣换团,后面參數(shù)個數(shù)的不定的 - 可變參數(shù)的定義:在定義參數(shù)類型的后面加上省略號
...
,比如func someFunction(argumentLabel parameterName: Int...)
宫蛆,parameterName
參數(shù)就是個可變參數(shù)了 - 可變參數(shù)的獲人野:在函數(shù)內(nèi)部,可變參數(shù)以數(shù)組的形式體現(xiàn)的耀盗,上面定義的那個可變參數(shù)的獲取方式
parameterName[0]
想虎,這樣,就拿到了可變參數(shù)的第一個值
// 可變參數(shù)
func optParameter(optionPara: Int...) {
for num in optionPara {
print(num)
}
}
// 調(diào)用可變參數(shù)函數(shù)
optParameter(optionPara: 1, 2, 3, 4, 5)
/**
輸出結(jié)果:
1
2
3
4
5
*/
1.7叛拷、輸入輸出參數(shù)(C語言中的指針參數(shù))
- 在C語言中舌厨,我們可以給函數(shù)傳入一個指針值,以達(dá)到在函數(shù)內(nèi)部修改外部參數(shù)值的目的忿薇,swift中裙椭,這種參數(shù)叫做
輸入輸出
參數(shù) - 定義一個輸入輸出參數(shù),只需要在參數(shù)類型前面加一個
inout
- 調(diào)用的時候署浩,需要在輸入輸出參數(shù)前面加"
&
" - 調(diào)用的時候揉燃,輸入輸出參數(shù)必須傳入變量,不能是常量
- 輸入輸出參數(shù)不能有默認(rèn)值
// 定義一個交換兩數(shù)的方法
func swap(a:inout Int, b:inout Int) {
let c = a
a = b
b = c
}
var a = 1
var b = 2
print("before: a=\(a), b=\(b)")
// 調(diào)用交換方法
swap(&a, &b)
print("after: a=\(a), b=\(b)")
/**
輸出結(jié)果:
before: a=1, b=2
after: a=2, b=1
*/
1.8筋栋、函數(shù)類型
- 回到開頭你雌,我說過,在swift中二汛,我們也可以稱為“一切皆對象”婿崭,那么,函數(shù)既然可以稱之為對象肴颊,肯定有類型
- 函數(shù)的類型:有個技巧氓栈,不管是什么類型,把參數(shù)名變量名全部刪掉婿着,剩下的就是類型了授瘦。上面的那個函數(shù),類型就應(yīng)該是
(inout Int, inout Int) -> Void
竟宋,解讀為:這個函數(shù)類型接受兩個輸入輸出的Int類型參數(shù)提完,并返回Void
- 函數(shù)類型的使用:同其他類型一樣的,上面那個函數(shù)類型就可以這樣使用
var function: (inout Int, inout Int) -> Void = swap
- 同樣丘侠,函數(shù)類型也可以作為函數(shù)的參數(shù)和返回值
函數(shù)作為參數(shù)的例子
// 這個函數(shù)用來作為參數(shù)
func sum(num1: Int, num2: Int) -> Int {
return num1+num2
}
// 這個函數(shù)接受一個(Int, Int)->Int類型的函數(shù)作為參數(shù)
func printResault(num1: Int, num2: Int, ruler:(Int, Int)->Int) {
// 調(diào)用傳進來的函數(shù)
print(ruler(num1, num2))
}
// 調(diào)用函數(shù)徒欣,并把參數(shù)傳進去
printResault(num1: 4, num2: 5, ruler: sum)
/**
輸出結(jié)果:
9
*/
函數(shù)作為返回值
// 減1
func stepForward(_ input: Int) -> Int {
return input + 1
}
// 加1
func stepBackward(_ input: Int) -> Int {
return input - 1
}
// 根據(jù)傳入的backward值,返回加1函數(shù)或者減1函數(shù)
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
// moveNearerToZero 現(xiàn)在指向 stepBackward() 函數(shù)蜗字。
//調(diào)用返回的函數(shù)
print(moveNearerToZero(currentValue))
/**
輸出結(jié)果:
2
*/
1.9打肝、嵌套函數(shù)
-
嵌套函數(shù)
就是在函數(shù)里面在定義一個函數(shù)脂新,相對的,前面說的那些都是全局函數(shù)
-
嵌套函數(shù)
只能在內(nèi)部使用
2粗梭、閉包
2.1争便、什么是閉包
- 閉包 就是“閉合包裹常量和變量的代碼塊”的簡稱,寫過OC的人對OC中的 Block 應(yīng)該不會陌生断医,其實閉包就是swift里面的“Block”
- 閉包是引用類型
- 閉包的定義和函數(shù)很像滞乙,把函數(shù)的各種名稱部分去掉,在用花括號括起來鉴嗤,其實就是一個閉包了酷宵,閉包的一般定義形式如下:
{(params) -> returnType in
statemems
}
-
in
關(guān)鍵字表示閉包的參數(shù)和返回值類型定義完成,閉包函數(shù)體開始 - 閉包參數(shù)可以是
inout
類型躬窜,但是浇垦,不能有默認(rèn)參數(shù) - 閉包完整格式實例
let grade = [90, 100, 80, 76, 88, 65, 65, 63]
print("before \(grade)")
let grade_sort = grade.sorted (by: { (num1: Int, num2: Int) -> Bool in
return num1 > num2
})
print("after \(grade_sort)")
/**
輸出結(jié)果:
before [90, 100, 80, 76, 88, 65, 65, 63]
after [100, 90, 88, 80, 76, 65, 65, 63]
*/
2.2閉包格式大簡化
- 函數(shù)參數(shù)為閉包的時候,編譯器可以自動推斷出閉包的類型的荣挨,比如說在下面的代碼中男韧,閉包的類型就可以省略,直接在括號內(nèi)寫參數(shù)名
- 閉包作為函數(shù)最后一個參數(shù)的時候默垄,可以省略函數(shù)調(diào)用的小括號此虑,直接把閉包跟在函數(shù)名后面,同時口锭,參數(shù)標(biāo)簽也可以省略掉朦前,這個閉包又稱做
尾隨閉包
,經(jīng)過這兩項優(yōu)化之后鹃操,上面的代碼變成了下面這樣
let grade = [90, 100, 80, 76, 88, 65, 65, 63]
print("before \(grade)")
let grade_sort = grade.sorted { (num1, num2) in
return num1 > num2
}
print("after \(grade_sort)")
/**
輸出結(jié)果:
before [90, 100, 80, 76, 88, 65, 65, 63]
after [100, 90, 88, 80, 76, 65, 65, 63]
*/
- 如果閉包中韭寸,只有一句代碼,那么閉包會自動把這句代碼的結(jié)果當(dāng)做返回值處理荆隘,也就是說恩伺,上面的閉包我們可以省略
return
關(guān)鍵字,省略之后椰拒,代碼如下
let grade = [90, 100, 80, 76, 88, 65, 65, 63]
print("before \(grade)")
let grade_sort = grade.sorted { (num1, num2) in
num1 > num2
}
print("after \(grade_sort)")
/**
輸出結(jié)果:
before [90, 100, 80, 76, 88, 65, 65, 63]
after [100, 90, 88, 80, 76, 65, 65, 63]
*/
- 在閉包中晶渠,參數(shù)可以使用縮寫,用
$
表示燃观,比如說$0
就是第一個參數(shù)褒脯,這時,前面的參數(shù)定義部分已經(jīng)沒有意義了缆毁,in
關(guān)鍵字也可以省略番川,代碼如下
let grade = [90, 100, 80, 76, 88, 65, 65, 63]
print("before \(grade)")
let grade_sort = grade.sorted { $0 > $1 }
print("after \(grade_sort)")
/**
輸出結(jié)果:
before [90, 100, 80, 76, 88, 65, 65, 63]
after [100, 90, 88, 80, 76, 65, 65, 63]
*/
2.3、逃逸閉包
-
逃逸閉包
指的是我們在函數(shù)內(nèi)部接收了閉包之后,把閉包保存了起來爽彤,留著函數(shù)結(jié)束之后再調(diào)用這個閉包,這個閉包就叫做逃逸閉包 - 逃逸閉包需要在定義的類型前加
@escaping
缚陷,否則會編譯報錯
// 定義一個變量适篙,用來存儲一個閉包,給后面使用
var completeHandle:() -> Void = {}
// 定義一個函數(shù)箫爷,這個函數(shù)接受一個閉包嚷节,并且設(shè)置給外部變量,這里必須標(biāo)記為 @escaping
func doSomeThing(completion: @escaping () -> Void) {
completeHandle = completion
}
print("設(shè)置之前")
// 調(diào)用函數(shù)虎锚,并設(shè)置一個閉包
doSomeThing {
print("完成了")
}
print("設(shè)置之后")
// 調(diào)用剛才設(shè)置好的閉包
completeHandle()
print("調(diào)用之后")
/**
輸出結(jié)果:
設(shè)置之前
設(shè)置之后
完成了
調(diào)用之后
*/
2.4硫痰、閉包中的self處理
- 有過OC經(jīng)驗的童鞋應(yīng)該都非常明白
Block
中不能強引用self
,否則會由于循環(huán)引用而導(dǎo)致內(nèi)存泄露 - Swift中提供了更加簡單的方法窜护,在閉包中弱引用一個變量效斑,只需要在閉包參數(shù)定義之前加入
[weak self]
,Swift就會自動將self
在閉包中弱引用 - 此時需要注意的是柱徙,弱引用可能不存在了缓屠,所以在這種情況下,
self
變成了一個可選值
{[weak self](params) -> returnType in
// self變成了可選值护侮,需要用?來使用
self?.somePropety = ...
statemems
}