美文网首页
Swift 之闭包

Swift 之闭包

作者: freemanIT | 来源:发表于2016-11-18 17:09 被阅读0次

    闭包

    闭包类似于 OC 的 block,但是比 OC 的 block 应用面更广

    • 在 OC 中 block 是匿名的函数
    • 在 Swift 中函数是特殊的闭包

    闭包的应用场景

    • 异步执行完成回调
    • 控制器间回调
    • 自定义视图回调

    回调特点

    • 以参数回调处理结果
    • 返回值为 Void

    代码

    • 定义一个函数
    //: 定义一个 sum 函数
            func sum(x: Int, y: Int) -> Int {
                return x + y
            }
            
            // 定义一个指向函数的常量
            // 在 Swift 中函数本身就可以当作参数被定义和传递
            let sumFunc = sum
            
            // 执行函数常量
            print(sumFunc(10, 30))
    
    • 闭包的四步演练
     // 1> 最简单的闭包
            let myBlock1 = {
                print("hello block")
            }
            
            myBlock1()
            
            // 2> 闭包的完整写法,闭包的所有内容都包含在 {} 中
            // `in` 用于区分闭包的参数和实现代码
            let myBlock2 = { () -> () in
                print("hello myBlock2")
            }
            
            myBlock2()
            
            // 3> 带参数的闭包
            let myBlock3 = { (x: Int, y: Int) -> () in
                print(x + y)
            }
            myBlock3(10, 20)
            
            // 4> 带返回值的闭包
            let myBlock4 = { (x: Int, y: Int) -> Int in
                return x + y
            }
            
            print(myBlock4(10, 50))
    

    GCD

    • 异步加载数据
     /// GCD 模拟异步加载数据
            func loadData() -> () {
                
                // GCD 概念:将任务添加到队列,并且指定任务的执行函数
                // 翻译 -> `队列` 调度 `任务` 以 `同步/异步` 方式执行
                DispatchQueue.global().async {
                    
                    print("异步耗时加载数据 \(Thread.current)")
                    
                    let json = ["新闻1", "新闻2", "出大事了"]
                    
                    DispatchQueue.main.async(execute: {
                        
                        print("主线程回调 \(Thread.current) \(json)")
                    })
                }
                
                print("come here")
            }
    

    添加回调闭包

    /// GCD 模拟异步加载数据
            func loadData(completion: @escaping ([String])->()) -> () {
                
                // GCD 概念:将任务添加到队列,并且指定任务的执行函数
                // 翻译 -> `队列` 调度 `任务` 以 `同步/异步` 方式执行
                DispatchQueue.global().async {
                    
                    print("异步耗时加载数据 \(Thread.current)")
                    
                    let json = ["新闻1", "新闻2", "出大事了"]
                    
                    DispatchQueue.main.async(execute: {
                        
                        print("主线程回调 \(Thread.current) \(json)")
                        
                        completion(json)
                    })
                }
                
                print("come here")
            }
    

    尾随闭包

    • 尾随闭包,如果闭包是最后一个参数,可以提前结束函数,最后一个参数直接使用 {} 闭包的方式传递
    // 尾随闭包写法
            // - 如果闭包是最后一个参数,函数可以提前结束,并且在末位直接追加 `{}` 闭包
            // - 尾随闭包可以省略参数名
            loadData { (result) in
                print("--- \(result)")
            }
            
            // 函数参数的写法
            loadData(completion: {result in
                print("--- \(result)")
            })
    

    闭包的循环引用

    • [weak self]

    • 表示闭包中的 self 是弱引用,如果 self 被释放,会自动设置为 nil

    • 与 OC 的 __weak 等效

    • [unowned self]

    • 表示闭包中的 self 是 assign 的,如果 self 被释放,指针地址保持不变,会出现野指针的错误

    • 与 OC 的 __unsafe_unretained 等效

    class ViewController: UIViewController {
                
                var finishedCallBack: (()->())?
                
                override func viewDidLoad() {
                    super.viewDidLoad()
                    
                    loadData {
                        // 与 OC 的 block 一样,闭包同样会对外部变量做一次 copy(强引用)
                        print("OK \(self)")
                    }
                }
                
                func loadData(completion: ()->()) -> () {
                    
                    // 使用属性记录闭包
                    finishedCallBack = completion
                    
                    DispatchQueue.global().async {
                        print("耗时操作")
                        
                        Thread.sleep(forTimeInterval: 1.0)
                        
                        DispatchQueue.main.async {
                            print("主线程回调")
                            
                            // 闭包是提前准备好的代码,在执行时需要指定上下文的语境,因此需要 `self.`
                            // 使用 `?` 表示一旦闭包不存在就什么都不做
                            // 使用 `!` 表示无论闭包是否存在都执行,如果真的不存在,会崩溃
                            self.finishedCallBack?()
                        }
                    }
                }
                
                // 析构函数 - 类似于 OC 的 dealloc
                deinit {
                    print(#function)
                }
            }
    

    解除循环引用

    // 1. 方法一,类似于 OC 的方法
            // * weak 修饰的变量有可能在运行时被修改为 nil,因此不能使用 let
            weak var weakSelf = self
            loadData {
                // 与 OC 的 block 一样,闭包同样会对外部变量做一次 copy(强引用)
                print("OK \(weakSelf)")
            }
    
      // 2. 方法二,Swift 的写法
            // [weak self] 表示闭包中的 self 是弱引用,如果 self 被释放,会自动设置为 nil
            // 与 OC 的 `__weak` 等效
            loadData { [weak self] in
                // 与 OC 的 block 一样,闭包同样会对外部变量做一次 copy(强引用)
                print("OK \(self?.view)")
            }
    
    // 3. 方法三
            // [unowned self] 表示闭包中的 self 是 assign 的,如果 self 被释放,指针地址保持不变
            // 会出现野指针的错误
            // 与 OC 的 `__unsafe_unretained` 等效
            loadData { [unowned self] in
                // 与 OC 的 block 一样,闭包同样会对外部变量做一次 copy(强引用)
                print("OK \(self.view)")
            }
    

    相关文章

      网友评论

          本文标题:Swift 之闭包

          本文链接:https://www.haomeiwen.com/subject/uhhspttx.html