Swift函數和閉包

簡介:本文主要講:函數的定義,外部參數的用處,無返回類型的三種函數定義方式html

閉包的定義,閉包的概念和用法,尾隨閉包的寫法,解除循環引用的方法swift

1、函數:

代碼實現

  • 函數的定義
    • 格式 func 函數名(行參列表) -> 返回值 {代碼實現}
    • 調用 let result = 函數名(值1, 參數2: 值2...)
func sum(a: Int, b: Int) -> Int { return a + b } let result = sum(10, b: 20) 
  • 沒有返回值的函數,一共有三種寫法
    • 省略
    • ()
    • Void
func demo(str: String) -> Void { print(str) } func demo1(str: String) -> () { print(str) } func demo2(str: String) { print(str) } demo("hello") demo1("hello world") demo2("olleh") 
  • 外部參數
    • 在形參名前再增長一個外部參數名,可以方便調用人員更好地理解函數的語義
    • 格式:func 函數名(外部參數名 形式參數名: 形式參數類型) -> 返回值類型 { // 代碼實現 }
    • Swift 2.0 中,默認第一個參數名省略


func sum1(num1 a: Int, num2 b: Int) -> Int { return a + b } sum1(num1: 10, num2: 20)

2、閉包:

與 OC 中的 Block 相似,閉包主要用於異步操做執行完成後的代碼回調,網絡訪問結果以參數的形式傳遞給調用方網絡

閉包的定義

  • 定義一個函數
//: 定義一個 sum 函數 func sum(num1 num1: Int, num2: Int) -> Int { return num1 + num2 } sum(num1: 10, num2: 30) //: 在 Swift 中函數自己就能夠看成參數被定義和傳遞 let mySum = sum let result = mySum(num1: 20, num2: 30) 
  • 定義一個閉包
    • 閉包 = { (行參) -> 返回值 in // 代碼實現 }
    • in 用於區分函數定義和代碼實現
//: 閉包 = { (行參) -> 返回值 in // 代碼實現 } let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in return x + y } sumFunc(num1: 10, num2: 20) 
  • 最簡單的閉包,若是沒有參數/返回值,則 參數/返回值/in 通通均可以省略
    • { 代碼實現 }
let demoFunc = { print("hello") }
 

基本使用

GCD 異步

  • 模擬在後臺線程加載數據
func loadData() { dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in print("耗時操做 \(NSThread .currentThread())") }) } 
  • 尾隨閉包,若是閉包是最後一個參數,能夠用如下寫法
  • 注意上下兩段代碼,} 的位置
func loadData() { dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("耗時操做 \(NSThread .currentThread())") } } 
  • 閉包的簡寫,若是閉包中沒有參數和返回值,能夠省略
func loadData() { dispatch_async(dispatch_get_global_queue(0, 0)) { print("耗時操做 \(NSThread .currentThread())") } } 

自定義閉包參數,實現主線程回調

  • 添加沒有參數,沒有返回值的閉包
override func viewDidLoad() { super.viewDidLoad() loadData { print("完成回調") } } // MARK: - 自定義閉包參數 func loadData(finished: ()->()) { dispatch_async(dispatch_get_global_queue(0, 0)) { print("耗時操做 \(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue()) { print("主線程回調 \(NSThread.currentThread())") // 執行回調 finished() } } } 
  • 添加回調參數



override func viewDidLoad() { super.viewDidLoad() loadData4 { (html) -> () in print(html) } } /// 加載數據 /// 完成回調 - 傳入回調閉包,接收異步執行的結果 func loadData4(finished: (html: String) -> ()) { dispatch_async(dispatch_get_global_queue(0, 0)) { print("加載數據 \(NSThread.currentThread())") dispatch_sync(dispatch_get_main_queue()) { print("完成回調 \(NSThread.currentThread())") finished(html: "<h1>hello world</h1>") } } }

循環引用

  • 創建 NetworkTools 對象
class NetworkTools: NSObject { /// 加載數據 /// /// - parameter finished: 完成回調 func loadData(finished: () -> ()) { print("開始加載數據...") // ... finished() } deinit { print("網絡工具 88") } } 
  • 實例化 NetworkTools 而且加載數據
class ViewController: UIViewController { var tools: NetworkTools? override func viewDidLoad() { super.viewDidLoad() tools = NetworkTools() tools?.loadData() { print("come here \(self.view)") } } /// 與 OC 中的 dealloc 相似,注意此函數沒有() deinit { print("控制器 88") } } 

運行不會造成循環引用,由於 loadData 執行完畢後,就會釋放對 self 的引用閉包

  • 修改 NetworkTools,定義回調閉包屬性
/// 完成回調屬性 var finishedCallBack: (()->())? /// 加載數據 /// /// - parameter finished: 完成回調 func loadData(finished: () -> ()) { self.finishedCallBack = finished print("開始加載數據...") // ... working() } func working() { finishedCallBack?() } deinit { print("網絡工具 88") } 

運行測試,會出現循環引用異步

解除循環引用

  • 與 OC 相似的方法
/// 相似於 OC 的解除引用 func demo() { weak var weakSelf = self tools?.loadData() { print("\(weakSelf?.view)") } } 
  • Swift 推薦的方法
loadData { [weak self] in print("\(self?.view)") } 
  • 還能夠
loadData { [unowned self] in print("\(self.view)") } 

閉包(Block) 的循環引用小結

  • Swiftasync

    • [weak self]
      • self是可選項,若是self已經被釋放,則爲nil
    • [unowned self]
      • self不是可選項,若是self已經被釋放,則出現野指針訪問
  • Objcide

    • __weak typeof(self) weakSelf;
      • 若是self已經被釋放,則爲nil
    • __unsafe_unretained typeof(self) weakSelf;
      • 若是self已經被釋放,則出現野指針訪問
相關文章
相關標籤/搜索