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

Swift3.0 - 真的很簡單
Swift3.0 - 數(shù)據(jù)類型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可選值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 對象和類
Swift3.0 - 屬性
Swift3.0 - 函數(shù)和閉包
Swift3.0 - 初始化和釋放
Swift3.0 - 協(xié)議protocol
Swift3.0 - 類和結(jié)構(gòu)體的區(qū)別
Swift3.0 - 枚舉
Swift3.0 - 擴展
Swift3.0 - 下標
Swift3.0 - 泛型
Swift3.0 - 異常錯誤
Swift3.0 - 斷言
Swift3.0 - 自動引用計數(shù)(strong,weak,unowned)
Swift3.0 - 檢測API
Swift3.0 - 對象的標識
Swift3.0 - 注釋
Swift3.0 - 元類型
Swift3.0 - 空間命名
Swift3.0 - 對象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 類簇
Swift3.0 - 動態(tài)調(diào)用對象(實例)方法
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")
 // 實現(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)."
}

中級思考

  • 參數(shù)和返回值

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

基本類型的值,對象,數(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)建一個接口,輸入true 返回 兩個數(shù)相加的函數(shù),輸入false 返回兩個數(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ù)輸入的條件返回對應的函數(shù)
if flag{
    return add
}else{
    return decrease
}
}
// 生成對應的函數(shù)
let addFunc = generateFuncByFlag(flag: false)
// 執(zhí)行返回的函數(shù)
print(addFunc(1,2))
  • 設置默認參數(shù)值
func addStudent(student:(name:String,score:Double)=("姓名",12)){
    print(student.name)
    print(student.1)
}
addStudent()
addStudent(student: ("酷走天涯",99))

提示:

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

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

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

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

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

提示:

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

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

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

提示:

報錯,不能使用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)

運行結(jié)果:

40
30

你需要注意的

1.inout的位置 在: 后面,數(shù)據(jù)類型前面
2.inout 修飾的參數(shù)不能有默認值
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ù)類型的變量不能用標簽修飾參數(shù)

// 錯誤的寫法  不能使用a,b標簽
var swap1:( a :inout Int, b: inout Int)->Void = swapTwoInts
// 你應該像下面這樣
var swap1:( _ :inout Int, _: inout Int)->Void = swapTwoInts
// 或者下面這樣也可以,a,b 不一定要和實際函數(shù)對應
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)

運行結(jié)果:

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

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)用的時候,沒有使用常量或者變量接受這個返回值,系統(tǒng)會產(chǎn)生警告如下圖

讓學習成為一種習慣

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

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

注意

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


高級思考

  • 如何獲取,函數(shù)自己的名稱,在那個文件中,在文件多少行
// 定義一個獲取獲取函數(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()

運行結(jié)果:

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

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

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

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

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

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

結(jié)果:

我是人類
我是女人

分析:

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

那么我們應該怎么處理這個問題呢?

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

運行結(jié)果:

我是男人
我是女人

下面這種寫法也是可以的

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

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

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

測試1

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

運行結(jié)果:

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

測試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)

運行:

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

提示

交換的必須是相同的對象

*@escaping 用法

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

運行

編譯報錯,提示沒有加@escaping

@escaping 作用

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

修改代碼

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

報錯提示:

downloadComplate 使用之前必須初始化

所以進行初始化

var downloadComplate:((Bool)->())! // 加? 也可以,但是在調(diào)用時,要進行解包
  func downloadResource(url:String,complate:@escaping (Bool)->())  {
  downloadComplate = complate
 // 異步下載,下載完成調(diào)動
  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.不加自動閉包的關(guān)鍵字@autoclosure

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

運行結(jié)果:

沒加@autoclosure

b.添加@autoclouse

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

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

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

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

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

完整的寫法其實是下面這樣

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))

提示:

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

d. @noescape

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

提示:

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

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

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