Swift文法基礎入門三(函數, 閉包),swift文法
Swift文法基礎入門三(函數, 閉包)
函數:
- 函數是用來完成特定任務的獨立的代碼塊。你給一個函數起一個合適的名字,用來標識函數做什麼,並且當函數需要執行的時候,這個名字會被用於“調用”函數
- 格式:
- func 函數名稱(參數名:參數類型, 參數名:參數類型...) -> 函數傳回值 { 函數實現部分 }
沒有參數沒有傳回值
func say() -> Void { print("hello")}say()func say1() -> () { print("hello")}say1()// 推薦func say2() { print("hello")}say2()
有參數沒有傳回值
內部/外部參數
- 內部參數: Swift2.0以前, 預設情況下的參數都是內部參數
- Swift2.0開始, 預設將第二個參數名稱作為外部參數
- 如果沒有明確地指定外部參數, 那麼系統預設會從第二個參數開始, 將參數的名稱作為外部參數
- 外部參數只能外部用, 函數內部不能使用, 函數內部只能使用內部參數
- 忽略外部參數: 在內部參數前加_
// Swift2.0之前, 預設是不會將第二個參數開始的參數名稱作為外部參數的, 必須自己手動指定func sum(i: Int, j: Int) { print(i + j)}sum(10, j: 20)func sum1(first i: Int, second j: Int) { print(i + j)}sum1(first: 10, second: 20)
預設參數(Default Parameter Values)
- 格式: func method(parameter: Int = 0){}
- 當預設值被定義後,調用這個函數時可以忽略這個參數
- 其它語言的預設參數必須寫在最後面, Swift可以寫在任意位置
注意
- 將帶有預設值的參數放在函數參數列表的最後。這樣可以保證在函數調用時,非預設參數的順序是一致的,同時使得相同的函數在不同情況下調用時顯得更為清晰。
func sum2(i: Int, j: Int = 10) { print(i + j)}//sum2(10, j: 20)sum2(10)// 不推薦這樣寫, 最好將預設參數寫在最後func sum3(i: Int = 20, j: Int) { print(i + j)}
常量參數和變數參數(Constant and Variable Parameters)
- 函數參數預設是常量, 在函數內部不能修改
- 如果想在函數中修改參數, 必須在參數前加上var
注意
- 對變數參數所進行的修改在函數調用結束後便消失了,並且對於函數體外是不可見的。變數參數僅僅存在於函數調用的生命週期中
func sum4(let i: Int, let j: Int) { print(i + j)}sum4(10, j: 20)var num1 = 10var num2 = 20//func swap(value1: Int, value2: Int){// let temp = value1// value1 = value2// value2 = temp//}// 注意: 操作的是局部變數, 對實參沒有影響func swap1(var value1: Int, var value2: Int){ print("互動前: value1 = \(value1), value2 = \(value2)") let temp = value1 value1 = value2 value2 = temp print("互動後: value1 = \(value1), value2 = \(value2)")}swap1(num1, value2: num2)print(num1)print(num2)
輸入輸出參數(In-Out Parameters)
- 變數參數,正如上面所述,僅僅能在函數體內被更改。如果你想要一個函數可以修改參數的值,並且想要在這些修改在函數調用結束後仍然存在,那麼就應該把這個參數定義為輸入輸出參數(In-Out Parameters)
- 定義一個輸入輸出參數時,在參數定義前加 inout 關鍵字
注意
- 輸入輸出參數不能有預設值,而且可變參數不能用 inout 標記。如果你用 inout 標記一個參數,這個參數不能被 var 或者 let 標記。
func swap2(inout value1: Int, inout value2: Int){ print("互動前: value1 = \(value1), value2 = \(value2)") let temp = value1 value1 = value2 value2 = temp print("互動後: value1 = \(value1), value2 = \(value2)")}swap2(&num1, value2: &num2)print(num1)print(num2)
可變參數(Variadic Parameters)
- 一個可變參數可以接收零個或多個值
- 如果沒有變參函數 , 並且函數的參數個數又不確定那麼只能寫多個方法或者用將函數參數改為集合
- 格式 func method(parameter: Int...){}
- 可變參數在函數中可以當做一個數組
注意
- 一個函數最多隻能有一個可變參數
- 變參只能是同種類型的資料
- 變參必須指定資料類型
- 如果函數有一個或多個帶預設值的參數,而且還有一個可變參數,那麼把可變參數放在參數表的最後
func sum5(numbers: Int...) {// print(numbers) var sum = 0 for number in numbers { sum += number } print(sum)}sum5(1, 2, 3)// 不推薦寫法, 和預設值一樣, 變參最好寫在最後func sum6(numbers: Int..., var sum: Int) { // print(numbers) for number in numbers { sum += number } print(sum)}sum6(1, 2, 3, sum: 0)// 推薦寫法func sum7(var sum: Int = 100, numbers: Int...) { // print(numbers) for number in numbers { sum += number } print(sum)}sum7(numbers: 1, 2, 3)// 一個函數中只能有一個變參//func sum8(numbers: Int..., values: Int...){// print(numbers)// print(values)//}// 有參數有傳回值func sum8(i: Int, j: Int) -> Int { return i + j}let result = sum8(10, j: 20)print(result)
閉包
閉包
// 正常寫法 loadData ({ () -> () in print("執行了") }) */ /* // 閉包的其它寫法 // 1.如果閉包是函數的最後一個參數, 那麼可以把閉包寫在調用函數的()後面 // 這種寫法, 我們稱之為 "尾隨閉包" loadData("123") { () -> () in print("執行了") } // 2.如果函數只接收一個參數, 並且這個參數是閉包, 那麼調用函數的()可以省略 // 這種寫法, 我們稱之為 "尾隨閉包" loadData { () -> () in print("執行了") }
func loadData(since_id: String, finished: ()->()) -> Void { dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("子線程做耗時操作 \(NSThread.currentThread())") dispatch_async(dispatch_get_main_queue(), { () -> Void in print("主線程更新UI \(NSThread.currentThread())") finished() }) } } /* func loadData(finished: ()->()) -> Void { dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("子線程做耗時操作 \(NSThread.currentThread())") dispatch_async(dispatch_get_main_queue(), { () -> Void in print("主線程更新UI \(NSThread.currentThread())") finished() }) } }
閉包的循環參考
- 閉包迴圈強引用
block
- 閉包和block很像, 都是提前準備好代碼, 在需要時執行
- block會對外部變數進行強引用, 保證執行代碼時變數還在
- block中用到self一定要非常小心 閉包
- 閉包也一樣, 會對外部變數進行強引用, 保證執行代碼時變數還在
- 如果您將閉包賦值給一個類執行個體的屬性,並且該閉包通過訪問該執行個體或其成員而捕獲了該執行個體,您將建立一個在閉包和該執行個體間的迴圈強引用
- Swift開發中能不寫self就不寫self, 一看到self就想到閉包
OC中如何解決循環參考
- __weak typeof(self) weakSelf = self;
- 特點: 對象釋放後會自動將變數賦值為nil
- __unsafe_unretained typeof(self) weakSelf = self;
- 特點: 對象釋放後不會自動將變數賦值為nil, 指向一塊廢棄的儲存空間
Swift中如何解決循環參考
應用情境:
- 什麼時候用weak
- 什麼時候用unowned
- 當被儲存的對象在使用時不會被提前釋放時就用unowned
捕獲列表
- 可以在
調用
閉包時在形參列表前面通過[]指定捕獲列表, 告訴系統如何處理指定的這些值
//weak var weakSelf = self //unowned var weakSelf = self callBack = { [unowned self ,weak btn = self.button] () -> () in //self.view.backgroundColor = UIColor.redColor() //weakSelf.view.backgroundColor = UIColor.redColor() self.view.backgroundColor = UIColor.redColor() print(btn) } loadData(callBack!) } func loadData(finished: ()->()) -> Void { dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("子線程做耗時操作 \(NSThread.currentThread())") dispatch_async(dispatch_get_main_queue(), { () -> Void in print("主線程更新UI \(NSThread.currentThread())") finished() }) } }
- 解構函式
- 析構器只適用於類類型,當一個類的執行個體被釋放之前,析構器會被立即調用
- 類似於OC中的dealloc方法
- 析構器是在執行個體釋放發生前被自動調用。你不能主動調用析構器
- 一般情況下, 當使用自己的資源時, 在解構函式中進行一些額外的清理
例如,如果建立了一個自訂的類來開啟一個檔案,並寫入一些資料,你可能需要在類執行個體被釋放之前手動去關閉該檔案
deinit { print("88") }
End