swift ARC
swift个属性也是通过指针的方式进行传递或者引用,则需要使用类似的Ojbect-C的智能指针的方式(ARC)
Ojbect-c有 __weak, __strong, __unsafe_unretained
swift则有与之对应的 weak, strong(默认使用strong), unowned
swift的所有赋值均为strong,但是因为使用ARC来管理追踪和管理内存则不可避免的会出现循环引用的问题
当出现循环引用的问题则需要使用weak或者unowned来解除循环引用的问题
一、weak
当引用的对象是可为空的时候,正常是使用weak
class Person { let name: String init(name: String) {self.name = name} var apartment: Apartment? deinit { print("\(name) is being deinitial") } } class Apartment { let unit: String init(unit: String) { self.unit = unit } weak var tenant: Person? deinit { print("Apartment \(unit) is being deinit") } }
如上所示,使用的是weak;并且注意Person后面有个? 表示是可为空的。
弱引用则说明该参数不一定要有值,可以为空所以需要?, 那么如果把?person后面的问好去掉是否可以,答案是不行的。
二、unowned
当引用的对象必须有值,但是又是循环引用的时候;此时解循环饮用的方法就是使用unowned;但是使用unowned需要注意该修饰的属性是否保证有效,如果无效则会导致程序的崩溃
class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } deinit { print("\(name) is being deinit") } } class CreditCard { let number: UInt64 unowned let customer: Customer init(number: UInt64, customer: Customer) { self.number = number self.customer = customer } deinit { print("Card #\(number) is being deinit") } }
如上所示,因为每张信用卡都要有一个对应的持有人,所以customer不能为空。但是因为customer跟creditcard产生了循环引用,则解循环引用的方法是使用unowned
如上分析的是从实际出发来判断是否使用unowned
那么如果想把customer改为可选的是否可以呢? 答案是可以的,可以这么声明该属性:unowned let customer: Customer? 那么customer就可为空。但是这样子操作其实可以使用weak直接操作,不需要使用unowned
使用weak修饰的属性如果无效之后则会变为空,无需担心改属性当前是否有效
三、循环闭包
如同objectc,swift的闭包也有捕获。
class HTMLElement { let name: String let text: String? lazy var asHTML: () -> String = { 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("\(name) is being deinit") } } var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello") print(paragraph!.asHTML()) paragraph = nil // <p>hello</p>
如上的结果只打印了<p>hello</p> 没有paragraph设为空之后的deinit的打印
出现该情况的原因是asHTML是HTMLElement的属性,但是asHTML内部却引用了self,导致HTMLElement拥有asHTML并且asHTML捕获了HTMLElement 的self则出现了循环引用
这里如果把捕获的self变为弱引用或者无主引用则不会出现循环引用的问题
可以这么修改
lazy var asHTML: () -> String = { [unowned self] in if let text = self.text { return "<\(self.name)>\(text)</\(self.name)>" } else { return "<\(self.name) />" } }
在闭包里面的参数列表之前描述捕获的状态为无主引用;类似的格式如下所示
lazy var someClosure: (Int, String) -> String = { [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in // closure body goes here }
各个捕获的参数使用逗号隔开
这里额外注意的,asHTML使用的是lazy。使用lazy的意思是使用到的时候才真正的进行初始化。那么如果这里把lazy去掉则会报错。因为在HTMLElement的成员未初始化完前(asHTML还没初始化),self是不可用的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!