美文网首页
闭包中的循环引用及解决方法

闭包中的循环引用及解决方法

作者: silasjs | 来源:发表于2019-01-20 11:05 被阅读3次

    闭包中的循环引用

    闭包中的循环引用原理和OC中的block类似。即对象A强引用了对象B,然后B也强引用了A。示例如下:

    class ViewController: UIViewController {
    
        var completionCallBack: (() -> ())?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            loadData {
                print(self.view)
            }
        }
        
        func loadData(completion: @escaping () -> ()) -> () {
            completionCallBack = completion
            DispatchQueue.global().async {
                print("耗时操作")
                Thread.sleep(forTimeInterval: 3)
                DispatchQueue.main.async(execute: {
                    print("主线程更新UI")
                    //回调执行闭包
                    completion()
                })
            }
            print("loadData最底部")
    }
    
    1. completionCallBack属性的定义及赋值可以看出:ViewController对象强引用了闭包completionCallBack
    2. loadData函数调用时的参数尾随闭包completionCallBack中强引用了ViewController对象

    解决方法

    解除循环引用,需要打断链条。

    1. OC中的方法:使用weak

    使用weak修饰变量,打破强引用,因为使用weak修饰的变量有一次变成nil的机会,所以需要注意解包。

    weak var weakSelf = self
    loadData {
        print(weakSelf?.view as Any)
    }
    

    2. swift中的方法:使用[weak self]

    使用[weak self]修饰闭包原理跟OC中的__weak类似,这样在闭包中使用self,就是弱引用。

    loadData { [weak self] in
        print(self?.view as Any)
    }
    

    3. swift中的方法:使用[unowned self]

    使用[unowned self]修饰闭包,跟OC中的__unsafe_unretained类似,不安全。

    loadData { [unowned self] in
        print(self.view as Any)
    }
    

    用析构函数检测是否解开了循环引用

    deinit {
        print("已销毁")
    }
    

    相关文章

      网友评论

          本文标题:闭包中的循环引用及解决方法

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