Swift語法基礎入門三(函數, 閉包)函數:函數是用來完成特定任務的獨立的代碼塊。你給一個函數起一個合適的名字,用來標識函數做什麼,並且當函數需要執行的時候,這個名字會被用於“調用”函數格式:func 函數名稱(參數名:參數類型, 參數名:參數類型...) -> 函數返回值 { 函數實現部分 }沒...
Swift語法基礎入門三(函數, 閉包)
函數:
- 函數是用來完成特定任務的獨立的代碼塊。你給一個函數起一個合適的名字,用來標識函數做什麼,並且當函數需要執行的時候,這個名字會被用於“調用”函數
- 格式:
- func 函數名稱(參數名:參數類型, 參數名:參數類型...) -> 函數返回值 { 函數實現部分 }
沒有參數沒有返回值
- 可以寫為 ->Void
- 可以寫為 ->()
- 可以省略
- Void。它其實是一個空的元組(tuple),沒有任何元素,可以寫成()
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 = 10
var 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)
閉包
閉包
- 閉包是自包含的函數代碼塊,可以在代碼中被傳遞和使用。Swift 中的閉包與 C 和 Objective-C 中的代碼塊(blocks)以及其他一些編程語言中的匿名函數比較相似
- 閉包可以捕獲和存儲其所在上下文中任意常量和變數的引用。這就是所謂的閉合併包裹著這些常量和變數,俗稱閉包
- 閉包的使用和block一樣, 用於保存一段代碼, 用作回調, 用作執行耗時操作
- 閉包格式: in關鍵字的目的是便於區分返回值和執行語句
{ (形參列表) -> 返回值類型 in 執行語句 }
// 正常寫法
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 var weakSelf = self
- weak 相當於OC中的 __weak, 和OC一樣 對象釋放後會自動將變數賦值為nil
-
所以被weak修飾的變數是可選類型
-
unowned var weakSelf = self
- unowned 相當於OC中的__unsafe_unretained, 和OC一樣, 對象釋放後不會自動將變數賦值為nil
-
所以被unowned修飾的變數, 不是可選類型
註意: weak和unowned只能修飾對象類型, 因為只有對象類型才有引用計數
-
應用場景:
- 什麼時候用weak
- 當被保存的對象有可能提前釋放時就用weak
- 什麼時候用unowned
- 當被保存的對象在使用時不會被提前釋放時就用unowned
- 什麼時候用weak
-
捕獲列表
- 可以在
調用
閉包時在形參列表前面通過[]指定捕獲列表, 告訴系統如何處理指定的這些值
- 可以在
//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")
}