循环引用问题

2017-08-01  本文已影响12人  coderST

1 在自己写项目的时候一直没有发现一个大的BUG,因为这个bug是在首页,是整个程序都一直运行的界面,除非用户手动退出,这个类是我自己封装的,后来在用到另外的项目的时候(不在首页了),发现该界面一直不走deinit方法,让我有点饶头啊!!!

   之前的定义
// frame : 给定的尺寸

// MARK:- 定义属性
    fileprivate var titles : [String]
    fileprivate var childsVC : [UIViewController]
    fileprivate var parentVC : UIViewController
    fileprivate var style : STPageViewStyle
    fileprivate var titleView : STTitlesView!
    fileprivate var titleViewParentView : Any?

    // titles : 标题的内容数组
    // childsVC : 对应标题控制器数组
    // parentVC : 父类控制器
    // style : 自定义数据
    // parentView : titleView被添加上的父类
    // titleViewParentView : 标题titleView被添加到哪里
let pageView = STPageView(frame: rect, titles: titles, childsVC: childsVC, parentVC: self, style: style, titleViewParentView: nil)

把从父类传进来的类,在定义属性前加weak进行弱引用

    fileprivate var titles : [String]
    fileprivate var childsVC : [UIViewController]
    `fileprivate weak var parentVC : UIViewController?`
    fileprivate var style : STPageViewStyle
    fileprivate var titleView : STTitlesView!
    fileprivate var titleViewParentView : Any?

2 如果产生循环引用的两个属性一个允许为nil,另一个不允许为nil,这种情况适合用无主引用来解决

class Dog {
    let name: String
    var food: Food?
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name)被销毁") }
}
class Food {
    let number: Int
    unowned var owner: Dog               // owner是一个无主引用
    init(number: Int, owner: Dog) {
        self.number = number
        self.owner = owner
    }
    deinit { print("食物被销毁") }
}

var dog1: Dog? = Dog(name: "Kate")
dog1?.food = Food(number: 6, owner: dog1!) // dog强引用food,而food对dog是无主引用

dog1 = nil                                 // 这样就可以同时销毁两个实例了

3. 如果产生循环引用的两个属性都必须有值,不能为nil,这种情况适合一个类使用无主属性,另一个类使用隐式解析可选类型

class Country {
    let name: String
    var capitalCity: City!                // 初始化完成后可以当非可选类型使用
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
    deinit { print("Country实例被销毁") }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
    deinit { print("City实例被销毁") }
}

// 这样一条语句就能够创建两个实例
var country: Country? = Country(name: "China", capitalName: "HangZhou")
print(country!.name)                        // China
print(country!.capitalCity.name)            // HangZhou
country = nil                               // 同时销毁两个实例

4 闭包也是引用类型,怎么解决闭包的循环强引用

class Element {
    let name: String
    let text: String?

    lazy var group:() -> String = {        // 相当于一个没有参数返回string的函数
        [unowned self] in                   // 定义捕获列表,将self变为无主引用
        if let text = self.text {           // 解包
            return "\(self.name), \(text)"
        }else {
            return "\(self.name)"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    deinit { print("\(name)被销毁") }
}

var element1: Element? = Element(name: "Alex", text: "Hello")
print(element1!.group())                     // Alex, Hello,闭包与实例相互引用

element1 = nil                               // self为无主引用,实例能被销毁

在闭包中定义一个捕获列表[unowned self],将self变为无主引用.这样就能够在避免产生循环强引用了.

参考

喵神的内存管理,WEAK 和 UNOWNED官方文档The Swift Programming Language的Language Guides部分的Automatic Reference Counting

上一篇下一篇

猜你喜欢

热点阅读