013-Swift3.0之循环强引用

一、解决实例属性之间的循环强引用

1.弱引用

// 定义一个Person(人)类
class Person {
    let name: String
    var apartment: Apartment? // 并不是每个人都有公寓,所以为可选型

    // 构造函数
    init(name: String) {
        self.name = name
    }

    // 析构函数
    deinit { print("\(name)被销毁") }
}

// 定义一个Apartment(公寓)类
class Apartment {
    let name: String

    // 注意:这里是弱引用,因为Person对Apartment强引用,Apartment对Person如果还是强引用,就会造成循环强引用,造成内存泄露
    weak var tenant: Person?  // 并不是每个公寓都有对应的人,所以为可选型

    // 构造函数
    init(name: String) { self.name = name }

    // 析构函数
    deinit { print("\(name)被销毁!") }
}

// 初始化创建一个Person(人)对象
var frank = Person(name: "Frank")
// 初始化创建一个Apartment(公寓)对象
var wanda = Apartment(name: "万达")
// 如果不是Apartment对Person的弱引用,就会造成彼此的循环强引用,造成内存泄漏
frank.apartment = wanda
wanda.tenant = frank

2.无主引用

// 定义一个Customer(拥有者)的类
class Customer {
    let name: String
    var card: CreditCard?  // 不是所有人都有信用卡,所以是可选型
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name)被销毁") }
}

// 定义一个CreditCard(信用卡)的类
class CreditCard {
    let number: UInt64
    unowned let customer: Customer  // 每一张信用卡有且仅有一个拥有者(无主引用)
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("卡号为\(number)的信用卡被销毁") }
}

// 定义一个Customer对象
var emma: Customer?
emma = Customer(name: "Emma")
emma!.card = CreditCard(number: 1234_5678_3434_9009, customer: emma!)  // 绑定信用卡
// 绑定信用卡的时候,其实就存在一个循环引用,好在信用卡只是对于拥有者是无助引用,所以没有造成循环强引用

3.无主引用以及隐式解析可选属性

// 定义一个Country(国家)类
class Country {
    let name: String
    // 这里capitalCity默认值为nil,但当Country一旦完成初始化任务,它的值就可以直接引用
    var capitalCity: City!   // 每一个国家有且仅有一个省会城市(隐式解析可选属性)
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

// 定义一个City(城市)类
class City {
    let name: String
    unowned let country: Country   // 每一个城市有且仅被一个国家拥有(无主引用)
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

// 定义一个Country对象
var country = Country(name: "China", capitalName: "Beijing")
print("\(country.name)的首都是\(country.capitalCity.name)")

1)当两个循环引用属性均为可选类型时,也就是均允许为nil,并且会产生潜在的循环强引用,这种场景最适合通过弱引用

2)当两个循环引用属性中一个属性为可选类型时,也就是只有一个允许为nil,而另一个属性的值不允许为nil,这也可能会产生循环强引用,这种场景适合通过无主引用

3)当两个循环引用属性都必须有值,并且初始化完成后永远不会为nil,这种场景需要一个类使用无主属性,而另外一个类使用隐式解析可选属性

 

二、解决闭包产生的循环强引用

// 定义一个HTMLElement(HTML标签)类
class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        [unowned self] in
        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("\(self.name)标签被销毁")
    }
}

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())

 

posted @ 2017-04-01 14:46  Frank9098  阅读(173)  评论(0)    收藏  举报