循环引用

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

Swift问题解决方案

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

弱引用(Weak Reference)

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

无主引用(Unowned Reference)

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

捕获列表(Capture List)

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

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

import UIKit

class 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 = woman
    woman!.boyFriend = man
    debugPrint("韩妹妹和李雷完成了人生使命,我们告诉arc这两个实例不再使用了。")
    debugPrint("woman 实例释放前,man.girlFriend 的值:\(man!.girlFriend)") //"woman 实例释放前,man.girlFriend 的值:Optional(StrongReferenceCycle.Female)"
    woman = nil
    debugPrint("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 = woman
    woman!.boyFriend = man
    debugPrint("韩妹妹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.两个类实例中的属性,一旦初始化后,都不能为nil
    var 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: String
    var girlFriend: Female? //这里互相引用
    init(name: String) {
        self.name = name
    }
    deinit {
        debugPrint("男人实例被销毁")
    }
}

class Female {
    let name: String
    var boyFriend: Male? //这里互相引用
    init(name: String) {
        self.name = name
    }
    deinit {
        debugPrint("女人实例被销毁")
    }
}

class Male2 {
    let name: String
    weak var girlFriend: Female2? //弱引用必须是变量,因为有可能在运行过程中值被修改了
    init(name: String) {
        self.name = name
    }
    deinit {
        debugPrint("男人2实例被销毁")
    }
}

class Female2 {
    let name: String
    weak var boyFriend: Male2? //弱引用必须是变量,因为有可能在运行过程中值被修改了
    init(name: String) {
        self.name = name
    }
    deinit {
        debugPrint("女人2实例被销毁")
    }
}

class Adult {
    let name: String
    init(name: String) {
        self.name = name
    }
    var child: Child?
    deinit {
        debugPrint("adult\(name)被销毁!")
    }
}

class Child {
    let name: String
    unowned var guardian:Adult //不能为nil的实例标注为unowned类型
    init(name: String, guardian: Adult) {
        self.name = name
        self.guardian = guardian
    }
    deinit {
        debugPrint("child\(name)被销毁!")
    }
}

class WeatherReport {
    let location: String
    let weather: String
    var 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 = location
        self.weather = weather
    }
    
    deinit {
        debugPrint("\(location)的天气预报实例被销毁!")
    }
    
}

class WeatherReport2 {
    let location: String
    let weather: String
    var 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 = location
        self.weather = weather
    }
    
    deinit {
        debugPrint("\(location)的天气预报实例被销毁!")
    }
    
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值