Swift3.0 - 函數(shù)和閉包

Swift3.0 - 真的很簡(jiǎn)單
Swift3.0 - 數(shù)據(jù)類型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可選值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 對(duì)象和類
Swift3.0 - 屬性
Swift3.0 - 函數(shù)和閉包
Swift3.0 - 初始化和釋放
Swift3.0 - 協(xié)議protocol
Swift3.0 - 類和結(jié)構(gòu)體的區(qū)別
Swift3.0 - 枚舉
Swift3.0 - 擴(kuò)展
Swift3.0 - 下標(biāo)
Swift3.0 - 泛型
Swift3.0 - 異常錯(cuò)誤
Swift3.0 - 斷言
Swift3.0 - 自動(dòng)引用計(jì)數(shù)(strong,weak,unowned)
Swift3.0 - 檢測(cè)API
Swift3.0 - 對(duì)象的標(biāo)識(shí)
Swift3.0 - 注釋
Swift3.0 - 元類型
Swift3.0 - 空間命名
Swift3.0 - 對(duì)象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 類簇
Swift3.0 - 動(dòng)態(tài)調(diào)用對(duì)象(實(shí)例)方法
Swift3.0 - 文本輸出
Swift3.0 - 黑魔法swizzle
Swift3.0 - 鏡像
Swift3.0 - 遇到的坑

函數(shù)的幾種類型

  • 無參無返
func greet() -> Void {
}
// 或者
func greet(){    
}
  • 有參無返
func greet(person: String, day: String) {
    return "Hello \\\\(person), today is \\\\(day)."
}
greet(person: "Bob", day: "Tuesday")

思考1: 如何省略外部參數(shù)名?

  greet("John", "Wednesday")
 // 實(shí)現(xiàn)代碼
  func greet(_ person: String, _ day: String) -> String {
    return "Hello \\\\(person), today is \\\\(day)."
}
  • 有參有返
func greet(_ person: String, on day: String) {
    return "Hello \\\\(person), today is \\\\(day)."
}
  • 無參有返
  func greet(_ person: String, on day: String) -> String {
    return "Hello \\\\(person), today is \\\\(day)."
}

中級(jí)思考

  • 參數(shù)和返回值

1.參數(shù)可以是那些道批?

基本類型的值,對(duì)象,數(shù)組,字典,元組,可變數(shù)量的參數(shù),函數(shù),閉包函數(shù),協(xié)議,結(jié)構(gòu)體,枚舉值

2.怎么定義參數(shù)

a. 單值

 func calculate(a:Int){
    let b = a
}

b.多值

func calculate(a:Int...){
    for _ in a{
     }
}
// 調(diào)用
calculate(a: 1,2,3,4,5,6)

c.元組

func calculate(a:(name:String,age:Int)){
    let name = a.name;
    let age = a.age;
}

d.數(shù)組

 func calculate(a:[String]){
    for student in a {
}
}

e.定義字典

 func calculate(a:[String:Int]){
    for student in a {
        print(student.key)
        print(student.value)
  }
}

f.函數(shù)作為參數(shù)

 func add(a:Int,b:Int)->Int{// 作為函數(shù)參數(shù)的函數(shù)
  return a+b
}

func calculate(a:(Int,Int)->Int){// 定義的參數(shù)為函數(shù)的函數(shù)
    a(2,1)// 執(zhí)行函數(shù)
}
calculate(a: add);// 執(zhí)行函數(shù)

g.上面函數(shù)的閉包寫法

  calculate { (a,b) -> Int in
    return a+b
}
calculate { (a,b) in a+b } // 省略寫法(由于swift有推斷能力,這樣寫它就能幫你推斷出來上面的寫法)

h. 參數(shù)為協(xié)議的方法

 protocol Player{  // 定義協(xié)議
      func play()
}

func playMusicWithPlayer(player:Player){
    player.play()
}

i.參數(shù)為結(jié)構(gòu)體

struct Student{
    var name:String
    var age:Int
};

func getStudentDescription(student:Student){
    print(student.name)
    print(student.age)
}

j.參數(shù)為枚舉類型

// 定義枚舉值
enum CarType:String{
  case Lincoln = "林肯"
  case MERCURY = "水星"
  case SUZUKI = "鈴木"
}
// 參數(shù)為協(xié)議的方法
func describeCar(carType:CarType){
    print(carType.rawValue);
}
  • 函數(shù)的內(nèi)部定義函數(shù)

需求: 創(chuàng)建一個(gè)接口,輸入true 返回 兩個(gè)數(shù)相加的函數(shù),輸入false 返回兩個(gè)數(shù)相減的函數(shù)

func generateFuncByFlag(flag:Bool)->(Int,Int)->Int{
// 定義兩數(shù)字相加函數(shù)
func add(a:Int,b:Int)->Int{
    return a+b;
}
// 定義兩數(shù)字相減函數(shù)
func decrease(a:Int,b:Int)->Int{
    return a-b;
}
// 根據(jù)輸入的條件返回對(duì)應(yīng)的函數(shù)
if flag{
    return add
}else{
    return decrease
}
}
// 生成對(duì)應(yīng)的函數(shù)
let addFunc = generateFuncByFlag(flag: false)
// 執(zhí)行返回的函數(shù)
print(addFunc(1,2))
  • 設(shè)置默認(rèn)參數(shù)值
func addStudent(student:(name:String,score:Double)=("姓名",12)){
    print(student.name)
    print(student.1)
}
addStudent()
addStudent(student: ("酷走天涯",99))

提示:

元組類型,不能分別給參數(shù)賦值,比如像下面這樣

// 這樣是錯(cuò)誤的方式
func addStudent(student:(name:String = "酷走天涯",score:Double = 12 )){
print(student.name)
print(student.1)
}
  • inout的使用

需求: 創(chuàng)建一個(gè)函數(shù),交換兩個(gè)Int類型值

a.如果參數(shù)為let修飾的常量

func swapTwoInts( a:  Int, b: Int){
let temporaryA = a
a = b
b = temporaryA
}

提示:

報(bào)錯(cuò):系統(tǒng)提示錯(cuò)誤,說常量不能修改值

b.我們將參數(shù)變成變量var

func swapTwoInts( var a:  Int, var b: Int){
let temporaryA = a
a = b
b = temporaryA
}

提示:

報(bào)錯(cuò),不能使用var 修飾參數(shù)

c.inout 修飾的參數(shù)可以修改值

func swapTwoInts(  a: inout Int, b:inout Int){
    let temporaryA = a
    a = b
    b = temporaryA
}
var a = 30
var b = 40
swapTwoInts(a: &a, b: &b)
print(a)
print(b)

運(yùn)行結(jié)果:

40
30

你需要注意的

1.inout的位置 在: 后面,數(shù)據(jù)類型前面
2.inout 修飾的參數(shù)不能有默認(rèn)值
3.inout 不能用于修飾多值(如a:Int...)

  • 定義函數(shù)類型的變量
  func swapTwoInts(  a: inout Int , b:inout Int){
    let temporaryA = a
    a = b
    b = temporaryA
  }

  var swap1:( inout Int, inout Int)->Void = swapTwoInts

注意:函數(shù)類型的變量不能用標(biāo)簽修飾參數(shù)

// 錯(cuò)誤的寫法  不能使用a,b標(biāo)簽
var swap1:( a :inout Int, b: inout Int)->Void = swapTwoInts
// 你應(yīng)該像下面這樣
var swap1:( _ :inout Int, _: inout Int)->Void = swapTwoInts
// 或者下面這樣也可以,a,b 不一定要和實(shí)際函數(shù)對(duì)應(yīng)
var swap1:( _ a:inout Int, _ b: inout Int)->Void = swapTwoInts
// 建議還是用下面這種
var swap1:( inout Int, inout Int)->Void = swapTwoInts
  • 定義閉包類型數(shù)據(jù)
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let customerProvider = { customersInLine.remove(at: 0)}
print(customersInLine.count)
print("Now serving \\\\(customerProvider())!")
print(customersInLine.count)

運(yùn)行結(jié)果:

5
Now serving Chris!
4
提示:上面那種閉包其實(shí)是五參有返的閉包形式,原形如下

let customerProvider:()->String= { customersInLine.remove(at: 0)}
  • 關(guān)鍵字 @discardableResult

先看一段代碼:

class OSStudent{
var name:String!
var score:Double!
func setNewScore(score:Double)->Bool{
    if name == nil || name.isEmpty{
    return false
    }
    self.score = score
    return true
}
}
OSStudent().setNewScore(score: 34.0)

注意:

函數(shù)的setNewScore 方法有返回值,但是調(diào)用的時(shí)候,沒有使用常量或者變量接受這個(gè)返回值,系統(tǒng)會(huì)產(chǎn)生警告如下圖

讓學(xué)習(xí)成為一種習(xí)慣

我們通過加關(guān)鍵字@discardableResult去除那種警告

@discardableResult
func setNewScore(score:Double)->Bool{
    if name == nil || name.isEmpty{
    return false
    }
    self.score = score
    return true
}

注意

如果你沒有添加這個(gè)關(guān)鍵字,系統(tǒng)默認(rèn)添加的是 @warn_unused_result ,有返回值沒有使用會(huì)發(fā)生警告


高級(jí)思考

  • 如何獲取,函數(shù)自己的名稱,在那個(gè)文件中,在文件多少行
// 定義一個(gè)獲取獲取函數(shù)名稱,獲取文件路徑的函數(shù)
func getFunctionName(name:String = #function,line:Int =   #line,file:String = #file){
print(name)
print(line)
print(file)
}
// 比如我們要獲取下面函數(shù)的信息,只需要將函數(shù)寫入要獲取信息函數(shù)的內(nèi)部調(diào)用即可
func  getUserName(){
 getFunctionName()
 }
 // 執(zhí)行函數(shù)
getUserName()

運(yùn)行結(jié)果:

getUserName()
152
/var/folders/gk/zc__29js08g1g03xrzgl8m1m0000gn/T/./lldb/2184/playground65.swift

  • 編譯器可能沒有那么智能
// 定義一個(gè)父類
class Person{
}
// 定義一個(gè)男人
class Man:Person{
}
// 定義一個(gè)女人
class Woman:Person{
}

// 定義三個(gè)描述人的方法
func describePerson(_ person:Person){
    print("我是人類")
}

func describePerson(_ woman:Woman){
    print("我是女人")
}

func describePerson(_ person:Man){
    print("我是男人")
}

 // 定義一個(gè)描述男人的女人的方法
func descripePerson(_ person:Person,_ woman:Woman){
  describePerson(person)
  describePerson(woman)
}
// 執(zhí)行
descripePerson(Man(), Woman())

結(jié)果:

我是人類
我是女人

分析:

參數(shù)man 在值沒有傳入之前,被默認(rèn)為Person 進(jìn)行編譯了,所以不管我們傳入男人或者女人都之調(diào)用人類描述的方法错英。

那么我們應(yīng)該怎么處理這個(gè)問題呢?

func descripePerson(_ person:Person,_ woman:Woman){
if person is Woman{
    describePerson(person as! Woman)
}else{
    describePerson(person as! Man)
}
describePerson(woman)
}

運(yùn)行結(jié)果:

我是男人
我是女人

下面這種寫法也是可以的

func descripePerson(_ person:Person,_ woman:Woman){
if let woman = person as?  Woman{
    describePerson(woman)
}else{
    describePerson(person as! Man)
}
describePerson(woman)
}
  • 泛型

需求: 設(shè)計(jì)一個(gè)接口,交換兩個(gè)元素(數(shù)字,字符,對(duì)象)的值

  func swap<T>(a:inout T,b:inout T){
    (a,b) = (b,a)
 }

測(cè)試1

var a = "你好"
var b = "酷走天涯"
print("交換前---------------------")
print(a)
print(b)
swap(&a, &b)
print("交換后----------------------")
print(a)
print(b)

運(yùn)行結(jié)果:

交換前---------------------
你好
酷走天涯
交換后----------------------
酷走天涯
你好

測(cè)試2

class Woman{
    var name = "女人"
    init(name:String) {
        self.name = name
    }
}
print("交換前---------------------")
print(a.name)
print(b.name)
swap(&a, &b)
print("交換后----------------------")
print(a.name)
print(b.name)

運(yùn)行:

交換前---------------------
小紅
小白
交換后----------------------
小白
小紅

提示

交換的必須是相同的對(duì)象

*@escaping 用法

var downloadComplate:(Bool)->()
func downloadResource(url:String,complate:(Bool)->()){
  downloadComplate = complate
  // 異步下載,下載完成調(diào)動(dòng)
  downloadComplate(true)
  // 下載失敗
  downloadComplate(false)
}

運(yùn)行

編譯報(bào)錯(cuò),提示沒有加@escaping

@escaping 作用

我們經(jīng)常在下載等異步操作完成時(shí),才調(diào)用閉包函數(shù),我們有可能暫時(shí)不要把這個(gè)閉包存放在數(shù)組中,或者使用屬性去引用它,那么這個(gè)時(shí)候就需要使用這個(gè)關(guān)鍵了

修改代碼

var downloadComplate:((Bool)->())
func downloadResource(url:String,complate:@escaping (Bool)->())  {
  downloadComplate = complate
 // 異步下載,下載完成調(diào)動(dòng)
  downloadComplate(true)
  // 下載失敗
  downloadComplate(false)
}

報(bào)錯(cuò)提示:

downloadComplate 使用之前必須初始化

所以進(jìn)行初始化

var downloadComplate:((Bool)->())! // 加? 也可以,但是在調(diào)用時(shí),要進(jìn)行解包
  func downloadResource(url:String,complate:@escaping (Bool)->())  {
  downloadComplate = complate
 // 異步下載,下載完成調(diào)動(dòng)
  downloadComplate(true)
  // 下載失敗
  downloadComplate(false)
}

我們?nèi)绾握{(diào)用

downloadResource(url: "www.baidu.com") { (flag) in
print(flag)
}

如果我們不需要引用完全可以不使用關(guān)鍵字@escaping

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure()
}
  • 關(guān)鍵字@autoclosure 的用法

a.不加自動(dòng)閉包的關(guān)鍵字@autoclosure

func serve(customer customerProvider: () -> String) {
    print(customerProvider())
}
serve { () -> String in
    return "沒加@autoclosure"
}

運(yùn)行結(jié)果:

沒加@autoclosure

b.添加@autoclouse

func serve(customer customerProvider: @autoclosure () -> String)     {
    print (customerProvider())
}
serve(customer: "加了@autoclosure") // 調(diào)用

是不是感覺參數(shù)像是字符串,而是下面這樣,系統(tǒng)幫你自動(dòng)閉包了

serve(customer: { "加了@autoclosure"})

如果還不清楚,其實(shí)是參數(shù)是一個(gè)返回值

serve(customer: { return "加了@autoclosure"})

完整的寫法其實(shí)是下面這樣

serve(customer: { () in return "加了@autoclosure"})

c. @autoclosure 和 @escaping 組合使用方法

func serve(customer customerProvider: @autoclosure @escaping() -> String) {
customerProvider1 = customerProvider
print (customerProvider())
}
serve(customer:  customersInLine.remove(at: 0))

提示:

其實(shí)自動(dòng)閉包給人可能造成一種表意不清的感覺,建議使用的時(shí)候,一定要注釋說明,或者不要使用。

d. @noescape

func calculate(fun :@noescape ()->()){
}

提示:

1.系統(tǒng)默認(rèn)為@onescape 的類型
2.不能被引用
3.不能在異步執(zhí)行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隆豹,一起剝皮案震驚了整個(gè)濱河市椭岩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌璃赡,老刑警劉巖判哥,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異碉考,居然都是意外死亡塌计,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事疑俭〖级螅” “怎么了伍玖?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剿吻。 經(jīng)常有香客問我窍箍,道長,這世上最難降的妖魔是什么丽旅? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任椰棘,我火速辦了婚禮,結(jié)果婚禮上榄笙,老公的妹妹穿的比我還像新娘邪狞。我一直安慰自己,他們只是感情好茅撞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布帆卓。 她就那樣靜靜地躺著,像睡著了一般米丘。 火紅的嫁衣襯著肌膚如雪剑令。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天拄查,我揣著相機(jī)與錄音吁津,去河邊找鬼。 笑死堕扶,一個(gè)胖子當(dāng)著我的面吹牛碍脏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稍算,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼潮酒,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了邪蛔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤扎狱,失蹤者是張志新(化名)和其女友劉穎侧到,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淤击,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匠抗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了污抬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汞贸。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绳军,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出矢腻,到底是詐尸還是另有隱情门驾,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布多柑,位于F島的核電站奶是,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏竣灌。R本人自食惡果不足惜聂沙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望初嘹。 院中可真熱鬧及汉,春花似錦、人聲如沸屯烦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漫贞。三九已至甸箱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迅脐,已是汗流浹背芍殖。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谴蔑,地道東北人豌骏。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像隐锭,于是被迫代替她去往敵國和親窃躲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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

  • 因?yàn)橐Y(jié)局swift3.0中引用snapKit的問題,看到一篇介紹Xcode8,swift3變化的文章,覺得很詳細(xì)...
    uniapp閱讀 4,403評(píng)論 0 12
  • 使用func 聲明一個(gè)函數(shù)钦睡。通過函數(shù)名稱和參數(shù)調(diào)用一個(gè)函數(shù)蒂窒。使用->區(qū)分參數(shù)名和函數(shù)返回的類型。 函數(shù)的參數(shù)可以有...
    民謠程序員閱讀 5,108評(píng)論 2 9
  • 函數(shù)的幾種類型 1.無參無返 2.有參無返 2.1 省略外部參數(shù)名 3.有參有返 4.無參有返 參數(shù)和返回值 1....
    元昊閱讀 188評(píng)論 0 0
  • 86.復(fù)合 Cases 共享相同代碼塊的多個(gè)switch 分支 分支可以合并, 寫在分支后用逗號(hào)分開荞怒。如果任何模式...
    無灃閱讀 1,354評(píng)論 1 5
  • 本章將會(huì)介紹 閉包表達(dá)式尾隨閉包值捕獲閉包是引用類型逃逸閉包自動(dòng)閉包枚舉語法使用Switch語句匹配枚舉值關(guān)聯(lián)值原...
    寒橋閱讀 1,554評(píng)論 0 3