Swift学习之自动引用计数

本文深入探讨Swift中的内存管理机制,包括引用计数、循环强引用、无主引用、闭包引起的循环强引用等问题,并提供了相应的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引用计数

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("Person:\(name) is being initialized")
    }

    deinit {
        print("\(name) is being deinitialized")
    }
}

var reference1:Person?
var reference2:Person?
var reference3:Person?

reference1 = Person(name: "iyaqi") //此时会打印:Person:iyaqi is being initialized
reference2 = reference1
reference3 = reference2

reference3 = nil
reference2 = nil
reference1 = nil // iyaqi is being deinitialized 在这才回销毁,因为有三个指针指向这块内存地址。arc 会再没有强指向的时候销毁该对象,收回地址
1.循环强引用
class Customer {
    let name : String
    init(name:String){self.name = name}
    var apartment:Apartment?
    deinit{
        print("\(name)is being deinited")
    }
}
class Apartment {
    let unit :String
    init(unit:String){self.unit = unit}
    weak var customer:Customer? // 加个weak 相当于apartment 的customer对象是弱引用,这样就不会引起强引用
    deinit{print("Apartment \(unit) is being deinited")}
}

var customer:Customer?
var apartment:Apartment?
customer = Customer.init(name: "iyaiq")
apartment = Apartment(unit: "19900619")
customer!.apartment = apartment
apartment!.customer = customer

//这两个操作不会触发任何deinit动作,因为相互引用,不会释放 加个weak ,就能解决这个问题
customer = nil
apartment = nil

//无主引用
class People{
    let name:String
    var card:CreditCard?
    init(name:String){
        self.name = name
    }
    deinit{print("name:\(name) is deinit")}
}
class CreditCard {
    let number:Int64
    unowned let people:People
    init(number:Int64,people:People){
        self.number = number
        self.people = people
    }
    deinit{print("CreditCard \(number) id deinit")}
}

var people :People?
people = People(name: "iyaqi")
let card = CreditCard(number: 1990, people: people!)
people!.card = card

people = nil //当people销毁的时候,这两个对象都会被销毁 Apartment 19900619 is being deinited,iyaqi is being deinitialized
2.无主引用和隐式解析
class Country {
    let name:String
    var city:City!
    init(name:String,city:String){
        self.name = name
        self.city = City(name:city, country: self)
    }
    deinit{print("Country:\(name) is deinit")}
}

class City {
    let name:String
    unowned var country:Country
    init(name:String,country:Country){
        self.name = name
        self.country = country
    }
    deinit{print("city:\(name) is deinit")}
}

var country:Country? = Country(name: "China", city: "beijing")
var city:City? = City(name: "beijing", country:country!)

print("\(city!.name)") //beijing

city = nil //city:beijing is deinit
country = nil //Country:China is deinit
3.闭包引起的循环强引用
class HtmlElement {
    let name:String
    let text:String?
    lazy var asHTML:Void -> 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("htmlElement is deinited")
    }
}

var htmlElement:HtmlElement? = HtmlElement(name:"p")
let defaultText = "some default text"
htmlElement!.asHTML = {
    return "<\(htmlElement!.name)>\(htmlElement!.text ?? defaultText)</\(htmlElement!.name)>"
}
print(htmlElement!.asHTML()) // <p>some default text</p>

htmlElement = nil//htmlElement is deinited 此时会触发deinit,因为在闭包没有使用self

var testHtmlElement:HtmlElement? = HtmlElement(name:"p",text:"hello world")
print(testHtmlElement!.asHTML()) //<p>hello world</p>
testHtmlElement = nil //此时并不会触发deinit,因为在闭包中使用了self
解决在闭包中引用了当前实例的方法
1.定义捕获列表:捕获列表和关键字in放在闭包最开始
2.弱引用和无主引用。
2.1在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为无主引用
2.2在被捕获的引用可能会变为nil时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为nil

class TestProtocol{

}

class TestClass {
    var delegate:TestProtocol?
    lazy var someClosure: Void -> String = {
        //在这里,代理可能为空,用弱引用。self跟闭包总是同时销毁,用无主引用。
        [unowned self, weak delegate = self.delegate!] in
        // 这里是闭包的函数体
        return "\(self)'s delegate is : \(self.delegate!)"
    }

    init(delegate:TestProtocol?){
        self.delegate = delegate
    }
}

let testProtocol = TestProtocol()
var testClass = TestClass(delegate: testProtocol)
print(testClass.someClosure()) //TestClass's delegate is : TestProtocol
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值