深入讲解Swift的内存管理
前言
LLVM编译器的好:Swift的内存管理除了要注意引用循环之外,几乎全部被LLVM编译器包揽,不需要开发人员操心。
Swift是自动管理内存的,这也就是说,我们不再需要操心内存的申请和分配。当我们通过初始化创建一个对象时,Swift会替我们管理和分配内存。而释放的原则遵循了自动引用计数(ARC)的规则:当一个对象没有引用的时候,其内存将会被自动回收。这套机制从很大程度上简化了我们的编码,我们只需要保证在合适的时候将引用置空(比如超过作用域,或者手动设为nil等),就可以确保内存使用不出现问题。
但是,所有的自动引用计数机制都有一个从理论上无法绕过的限制,那就是循环引用(retaincycle)的情况。
引用循环问题是什么
Swift使用ARC(自动引用计数)的方法为引用类型管理内存。
在Swift中,当声明引用类型的变量并将对象负值给他时,相当于创建了对该对象的强引用,该对象的引用计数将加1。如果两个对象相互强引用,将导致引用循环。引用循环一旦出现,相关的对象将无法释放,从而产生内存泄漏。
引用循环问题出现的场景与解决办法
Swift中类对象和闭包都是通过引用进行传值,所以以下场景会出现引用循环:
类对象相互强引用
两个对象彼此引用对方时,形成引用循环。
classLetter{ letaddressedTo:String varmailbox:MailBox? init(addressedTo:String){ self.addressedTo=addressedTo } deinit{ printl("Theletteraddressedto\(addressedTo)isbeingdiscarded") } } classMailBox{ letpoNumber:Int varletter:Letter? init(poNumber:Int){ self.poNumber=poNumber } deinit{ print("P.OBox\(poNumberisgoingaway)") } }
Letter类中强引用了MailBox类对象,MailBox类中又强引用了Letter类对象形成引用循环。
解决办法:声明对象时加入weak关键字(弱引用)可以解除强引用。比如将letter对象声明为weak时,mailbox对象的引用计数不会加1,从而解除引用循环。一般将逻辑上属于另一对象的对象声明为弱对象。如:
weakvarletter:Letter?
闭包中引用包含自身的对象
闭包中引用包含自身的对象也会造成引用循环。
classMailChecker{ letmailbox:MailBox letletter:Letter lazyvarwhoseMail:()->String={ return"Letterisaddressedto\(self.letter.addressedTo)" } init(name:String){ self.mailbox=MailBox(poNumber:311) self.letter=Letter(addressedTo:name) } deinit{ println("classisbeingdeintialized") } }
示例代码中whoseMail的闭包中使用self引用了包含自身的MailChecker对象,此时该闭包拥有MailChecker对象,而MailChecker对象又拥有该闭包,导致引用循环。
解决办法:此时可以添加[unownedself]让Swift知道不应保留self对象,从而解除引用循环。将闭包改为:
lazyvarwhoseMail:()->String={[unownedself]in return"Letterisaddressedto\(self.letter.addressedTo)" }
注:代码均取自BoisyG.Pitre《Swift基础教程》
总结
以上就是这篇文章的全部内容了,希望本文的内容对各位iOS开发者们能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。