最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

循环引用

运维笔记admin71浏览0评论

循环引用

循环引用

首先一张图解释一下循环引用

Swift问题解决方案

为了解决这个问题,swift提供了三种基本的解决方案,如下:

弱引用(Weak Reference)

如果被指向的实例有可能为nil,则使用弱引用

无主引用(Unowned Reference)

如果被指向的实例不为nil,则使用无主引用

捕获列表(Capture List)

如果在类属性使用闭包时,且闭包体内引用当前实例self而产生强引用环时,则使用捕获列表

下面对这三种方法和使用的情况分别做解释说明

import UIKitclass ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()//强引用例子strongReferenceMethod()//解决方法一,弱引用例子,被指向的实例有可能为nil的时候weakReferenceMethod()//解决方法二,无主引用,被指向的实例不能为nil的时候unownedReferenceMethod()//解决方法三,捕获列表.如果在类属性使用闭包时,且闭包内引用当前实例self而产生强引用环时,则使用捕获列表captureListMethod()}
}func strongReferenceMethod() {var man:Male? = Male(name: "李雷")var woman:Female? = Female(name: "韩梅梅")man!.girlFriend = womanwoman!.boyFriend = mandebugPrint("韩妹妹和李雷完成了人生使命,我们告诉arc这两个实例不再使用了。")debugPrint("woman 实例释放前,man.girlFriend 的值:\(man!.girlFriend)") //"woman 实例释放前,man.girlFriend 的值:Optional(StrongReferenceCycle.Female)"woman = nildebugPrint("woman 实例释放后,man.girlFriend 的值:\(man!.girlFriend)")man = nil //"woman 实例释放后,man.girlFriend 的值:Optional(StrongReferenceCycle.Female)"//可以看到并没有调用对应的dealloc销毁方法
}func weakReferenceMethod() {var man:Male2? = Male2(name: "李雷2")var woman:Female2? = Female2(name: "韩梅梅2")man!.girlFriend = womanwoman!.boyFriend = mandebugPrint("韩妹妹2和李雷2完成了人生使命,我们告诉arc这两个实例不再使用了。")debugPrint("woman 实例释放前,man.girlFriend 的值:\(man!.girlFriend)")//"woman 实例释放前,man.girlFriend 的值:Optional(StrongReferenceCycle.Female2)"debugPrint("man 实例释放前,woman.boyFriend 的值:\(woman!.boyFriend)")//"man 实例释放前,woman.boyFriend 的值:Optional(StrongReferenceCycle.Male2)"woman = nil //"女人2实例被销毁"debugPrint("woman 实例释放后,man.girlFriend 的值:\(man!.girlFriend)")//"woman 实例释放后,man.girlFriend 的值:nil"man = nil //"男人2实例被销毁"debugPrint("man 实例释放后,woman.boyFriend  的值:\(woman?.boyFriend )")//"man 实例释放后,woman.boyFriend  的值:nil"这里需要使用woman?来进行解包,否则因为woman已经是nil了,如果强制解包就会报错//这里可以看到swift会主动保护弱引用的值。如man实例中的弱引用girlfriend属性,他指向的是woman属性,所以当woman实例释放,则girlfriend值会被swift重置为nil
}func unownedReferenceMethod() {//无主引用总是假定其引用对象一直存在(有值),因而无主引用不能修饰可选类型。使用场景1.其中一个类实例中国的属性为可选类型,即其值可以为nil,而另一个实例中的属性为非可选类型,即不能为nil。场景2.两个类实例中的属性,一旦初始化后,都不能为nilvar stark: Adult?stark = Adult(name: "柰徳.斯塔克")stark!.child = Child(name: "罗伯.斯塔克", guardian: stark!)stark = nil
}func captureListMethod() {var weatherReport: WeatherReport? = WeatherReport(location: "成都", weather: "多云")debugPrint("\(weatherReport!.reports())") //"成都的天气预报是:多云"weatherReport = nil //但是这个执行后并没有调用dealloc方法释放var weatherReport2: WeatherReport2? = WeatherReport2(location: "成都", weather: "多云")debugPrint("\(weatherReport2!.reports())") //"成都的天气预报是:多云"weatherReport2 = nil //"成都的天气预报实例被销毁!" 这里可以看到正确执行了dealloc方法
}class Male {let name: Stringvar girlFriend: Female? //这里互相引用init(name: String) {self.name = name}deinit {debugPrint("男人实例被销毁")}
}class Female {let name: Stringvar boyFriend: Male? //这里互相引用init(name: String) {self.name = name}deinit {debugPrint("女人实例被销毁")}
}class Male2 {let name: Stringweak var girlFriend: Female2? //弱引用必须是变量,因为有可能在运行过程中值被修改了init(name: String) {self.name = name}deinit {debugPrint("男人2实例被销毁")}
}class Female2 {let name: Stringweak var boyFriend: Male2? //弱引用必须是变量,因为有可能在运行过程中值被修改了init(name: String) {self.name = name}deinit {debugPrint("女人2实例被销毁")}
}class Adult {let name: Stringinit(name: String) {self.name = name}var child: Child?deinit {debugPrint("adult\(name)被销毁!")}
}class Child {let name: Stringunowned var guardian:Adult //不能为nil的实例标注为unowned类型init(name: String, guardian: Adult) {self.name = nameself.guardian = guardian}deinit {debugPrint("child\(name)被销毁!")}
}class WeatherReport {let location: Stringlet weather: Stringvar temperature: Int?//因为该计算属性使用到闭包且闭包中使用了self,所以必须是惰性属性.因为此时self和其他使用到的属性有可能还没有初始化完成就执行了reports属性内部的操作lazy var reports: ()->String = {if self.temperature != nil {return "\(self.location)的天气预报是: \(self.weather), 气温是\(self.temperature)"} else {return "\(self.location)的天气预报是:\(self.weather)"}}init(location: String, weather: String) {self.location = locationself.weather = weather}deinit {debugPrint("\(location)的天气预报实例被销毁!")}}class WeatherReport2 {let location: Stringlet weather: Stringvar temperature: Int?//因为该计算属性使用到闭包且闭包中使用了self,所以必须是惰性属性.因为此时self和其他使用到的属性有可能还没有初始化完成就执行了reports属性内部的操作lazy var reports: ()->String = {[weak self] in //[weak self] in 和 [unowned self] in作用一样,区别见前面的weak和unowned的解释if self!.temperature != nil {return "\(self!.location)的天气预报是: \(self!.weather), 气温是\(self!.temperature)"} else {return "\(self!.location)的天气预报是:\(self!.weather)"}}init(location: String, weather: String) {self.location = locationself.weather = weather}deinit {debugPrint("\(location)的天气预报实例被销毁!")}}

 

 

发布评论

评论列表(0)

  1. 暂无评论