• Swift-08-闭包引起的循环强引用


      循环强引用还会发生在当你将一个闭包赋值给类实例的某个实例,并且这个闭包体中又实用了这个类实例。这个闭包体重可能访问了实例的某个属性,例如self.**,或者闭包中调用了实例的某个方法,例如self.**,这两种情况都导致闭包“捕获”self,从而产生了循环强引用。

      循环强引用的产生,是因为闭包和类相似,都是引用类型。当你把闭包赋值给某个属性时,你也把一个引用赋值给了这个闭包。实质上,这跟之前的问题一样,两个强引用让彼此一直有效。但是,和两个类实例不同,这次一个是类实例,另一个是闭包。

      Swift提供了一种优雅的方法来解决这个问题,称之为闭包捕获列表。

      在定义闭包时,同时定义捕获列表作为闭包的一部分,通过这种方式可以解决闭包和类实例之间的循环强引用。捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。跟解决两个类实例间的循环强引用一样,声明每个捕获的引用为弱引用或无主易用,而不是强引用。应该根据代码关系来决定使用弱引用还是无主引用。

      ----------定义捕获列表

      捕获列表中的每一项都由一对元素组成,一个元素是weak或unowned关键字,另一个元素是类实例的引用(如self)或初始化过的变量(如delegate = self.delegate!)。这些项在方括号中用逗号分开。

      如果闭包有参数列表和返回类型,把捕获列表放在它们前面:

      如果闭包没有指明参数列表或者返回类型,即他们会通过上下文来判断,那么可以把捕获列表和关键字in放在闭包最开始的地方。

      ----------弱引用和无主引用

      在闭包和捕获的实例总是互相引用时并且总是同时销毁时,将闭包内的捕获定义为无主引用。

      相反的,在被捕获的引用可能会变为nil时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为nil。这使我们可以在闭包体内检查他们是否存在。

      注意:如果被捕获的引用绝对不会变为nil,应该用无主引用,而不是弱引用。

    class HTMLElement {
        let name:String
        let text:String?
        
        lazy var asHTML:Void -> String = {
            [unowned self] in //表示“用无主引用而不是强引用来捕获 self ”
            if let text = self.text{
                return "<(self.name)> (text)<(self.name)>"
            }else{
                return "<(self.name)>"
            }
        }
        
        init(name:String, text:String? = nil){
            self.name = name
            self.text = text
        }
        
        deinit{
            print("(name) is being deinitialized")
        }
    }
    
    var paragraph:HTMLElement? = HTMLElement(name: "p", text: "hello world")
    print(paragraph!.asHTML())
    

      打印:

    <p> hello world<p>

     

    这个闭包这个地方,没有看懂。

  • 相关阅读:
    计数问题
    自定义中间件
    中间件的数据流向
    模块化
    开发属于自己的包
    中间件
    java JDK环境变量配置
    uni-app 请求 uni.request封装使用
    uni-app 自定义 简单 底部tab
    vue 过滤器 filter 的使用
  • 原文地址:https://www.cnblogs.com/tanglimei/p/5134076.html
Copyright © 2020-2023  润新知