Swift3入門教程之二----函數(shù)和閉包

我的博客地址: 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)簽髓需,recipientshouting是參數(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
}

相關(guān)文章

1敌完、Swift3入門教程之一基礎(chǔ)部分

參考資料:

  1. Swift Standard Library Playground
  2. Swift.org
  3. The Swift Programming Language (Swift 3)
  4. Using Swift with Cocoa and Objective-C (Swift 3)
  5. WWDC2016:Session 404 Getting Started with Swift
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市羊初,隨后出現(xiàn)的幾起案子滨溉,更是在濱河造成了極大的恐慌,老刑警劉巖长赞,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晦攒,死亡現(xiàn)場離奇詭異,居然都是意外死亡得哆,警方通過查閱死者的電腦和手機勤家,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柳恐,“玉大人伐脖,你說我怎么就攤上這事±稚瑁” “怎么了讼庇?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長近尚。 經(jīng)常有香客問我蠕啄,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任歼跟,我火速辦了婚禮和媳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哈街。我一直安慰自己留瞳,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布骚秦。 她就那樣靜靜地躺著她倘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪作箍。 梳的紋絲不亂的頭發(fā)上硬梁,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機與錄音胞得,去河邊找鬼荧止。 笑死,一個胖子當(dāng)著我的面吹牛阶剑,可吹牛的內(nèi)容都是我干的罩息。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼个扰,長吁一口氣:“原來是場噩夢啊……” “哼瓷炮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起递宅,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤娘香,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后办龄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烘绽,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年俐填,在試婚紗的時候發(fā)現(xiàn)自己被綠了安接。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡英融,死狀恐怖盏檐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驶悟,我是刑警寧澤胡野,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站痕鳍,受9級特大地震影響硫豆,放射性物質(zhì)發(fā)生泄漏龙巨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一熊响、第九天 我趴在偏房一處隱蔽的房頂上張望旨别。 院中可真熱鬧,春花似錦汗茄、人聲如沸秸弛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽胆屿。三九已至奥喻,卻和暖如春偶宫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背环鲤。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工纯趋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冷离。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓吵冒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親西剥。 傳聞我的和親對象是個殘疾皇子痹栖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容