IOS中解决ARC类实例间循环引用(Swfit)
来源:互联网 发布:java mvc框架下载 编辑:程序博客网 时间:2024/06/05 17:05
原创Blog,转载请注明出处
http://blog.csdn.net/column/details/swfitexperience.html
备注:本文代码和图片主要来自于官方文档
不熟悉ARC的同学可以看看前一篇关于ARC的简述,这个是我的Swfit教程专栏
http://blog.csdn.net/column/details/swift-hwc.html
一、几个用到的关键概念
弱引用(weak):不会增加自动引用计数,必须为可选类型变量,因为弱引用在引用计数为0的时候,会自动赋为nil。在swfit中,可以赋值为nil的为可选类型
无主引用(unonwed):不会增加自动引用计数,必须为非可选类型。在ARC销毁内存后,不会被赋为nil,所以在访问无主引用的时候,要确保其引用正确,不然会引起内存崩溃。
隐式解析可选类型:在初始的时候可以为nil,但是第一次赋值以后便会一直有值。语法是在变量后面加上感叹号(例如var name:String!)。使用该类型只需要正常调用,不需要像可选类型那样做判断。
二、类实例之间的循环引用
1、实例A可选包含实例B的引用,实例B可选包含实例A的引用-用弱引用来解决
举例:
下面两个类,公寓不一定有住户,住户也不一定在公寓里
反面教材:两个都是强引用会导致循环引用
然后将两个强引用断开后,本应该释放的内存
由于两个实例相互存在强引用(引用计数一直为1),所以这块内存一直没办法释放。
解决方案,采用弱引用,
然后将两个强引用断开后,
这时候,Person引用计数为0,Apartment实例引用计数为1
由于Person实例引用计数为0,Person内存被释放,导致Apartment实例引用计数为0,内存被释放
2、实例A可选包含实例B,实例B一定包含实例A-用无主引用解决
举例
用户可能没有信用卡,但是信用卡一定会有用户。由于信用卡一定有用户,所以不是可选类型,不能用弱引用,swift中提供的无主引用是简单便捷的解决方案。
这样内存如图2.1,此时用户实例引用为1,信用卡实例引用为1
用户注销后,
join = nil
那么用户实例引用计数为0,导致用户实例被释放,导致信用卡实例引用为0,内存释放,如图2.2
看到这,聪明的同学会问了:由于Customer中的信用卡是可选的,我把它设为弱引用不能解决这个问题吗?
举例
此时的内存模型
可以看到问题了吧?由于card只有一个弱引用,也就是引用计数为0,这样的对象在创建之后就会被释放掉。所以,没办法实现上述功能了。
3、A一定包含B,B一定包含A - 用隐式解析+无主引用解决
举例:国家一定包含首都,首都也一定在一个国家里
这里,Country的构造函数里,City要调用self,而只有Country的实例完全初始化结束后才能调用self。所以,capitialCity设为隐式可选类型,让他默认为nil,这样构造过程的第一阶段就可以不包括captialCity,就可以把self赋值给Country赋值给capittalCity了。
想详细看看构造过程的两个阶段,参照我之前写的构造过程文章,还不懂的话请留言。
这样设计的意义是:可以通过一条构造与巨还构造国家和首都两个实例,并且可以不用可选解析的方式来访问首都实例。
http://blog.csdn.net/column/details/swfitexperience.html
备注:本文代码和图片主要来自于官方文档
不熟悉ARC的同学可以看看前一篇关于ARC的简述,这个是我的Swfit教程专栏
http://blog.csdn.net/column/details/swift-hwc.html
一、几个用到的关键概念
弱引用(weak):不会增加自动引用计数,必须为可选类型变量,因为弱引用在引用计数为0的时候,会自动赋为nil。在swfit中,可以赋值为nil的为可选类型
无主引用(unonwed):不会增加自动引用计数,必须为非可选类型。在ARC销毁内存后,不会被赋为nil,所以在访问无主引用的时候,要确保其引用正确,不然会引起内存崩溃。
隐式解析可选类型:在初始的时候可以为nil,但是第一次赋值以后便会一直有值。语法是在变量后面加上感叹号(例如var name:String!)。使用该类型只需要正常调用,不需要像可选类型那样做判断。
二、类实例之间的循环引用
1、实例A可选包含实例B的引用,实例B可选包含实例A的引用-用弱引用来解决
举例:
下面两个类,公寓不一定有住户,住户也不一定在公寓里
反面教材:两个都是强引用会导致循环引用
class Person {let name: Stringinit(name: String) { self.name = name }var apartment: Apartment?deinit { println("\(name) is being deinitialized") }}class Apartment {let number: Intinit(number: Int) { self.number = number }var tenant: Person?deinit { println("Apartment #\(number) is being deinitialized") }}var john: Person?var number73: Apartment?john = Person(name: "John Appleseed")number73 = Apartment(number: 73)john!.apartment = number73number73!.tenant = john然后,这样就形成了循环引用(此时两个实例引用计数都为2),如图1.1
然后将两个强引用断开后,本应该释放的内存
john = nilnumber73 = nil这时候内存如图1.2
由于两个实例相互存在强引用(引用计数一直为1),所以这块内存一直没办法释放。
解决方案,采用弱引用,
class Person {let name: Stringinit(name: String) { self.name = name }var apartment: Apartment?deinit { println("\(name) is being deinitialized") }}class Apartment {let number: Intinit(number: Int) { self.number = number }weak var tenant: Person?deinit { println("Apartment #\(number) is being deinitialized") }}var john: Person?var number73: Apartment?john = Person(name: "John Appleseed")number73 = Apartment(number: 73)john!.apartment = number73number73!.tenant = john此时,内存图如图1.3,此时Person实例引用计数为1,Apartment实例引用计数为2
然后将两个强引用断开后,
john = nilnumber73 = nil内存如图1.4
这时候,Person引用计数为0,Apartment实例引用计数为1
由于Person实例引用计数为0,Person内存被释放,导致Apartment实例引用计数为0,内存被释放
2、实例A可选包含实例B,实例B一定包含实例A-用无主引用解决
举例
用户可能没有信用卡,但是信用卡一定会有用户。由于信用卡一定有用户,所以不是可选类型,不能用弱引用,swift中提供的无主引用是简单便捷的解决方案。
class Customer { let name: String var card: CreditCard? init(name: String) { self.name = name } deinit { println("\(name) is being deinitialized") }}class CreditCard { let number: Int unowned let customer: Customer init(number: Int, customer: Customer) { self.number = number self.customer = customer } deinit { println("Card #\(number) is being deinitialized") }}var john: Customer?john = Customer(name: "John Appleseed")john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
这样内存如图2.1,此时用户实例引用为1,信用卡实例引用为1
用户注销后,
join = nil
那么用户实例引用计数为0,导致用户实例被释放,导致信用卡实例引用为0,内存释放,如图2.2
看到这,聪明的同学会问了:由于Customer中的信用卡是可选的,我把它设为弱引用不能解决这个问题吗?
举例
class Customer { let name: String weak var card: CreditCard? init(name: String) { self.name = name } deinit { println("\(name) is being deinitialized") }}class CreditCard { let number: Int let customer: Customer init(number: Int, customer: Customer) { self.number = number self.customer = customer } deinit { println("Card #\(number) is being deinitialized") }}var john: Customer?john = Customer(name: "John Appleseed")john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
此时的内存模型
可以看到问题了吧?由于card只有一个弱引用,也就是引用计数为0,这样的对象在创建之后就会被释放掉。所以,没办法实现上述功能了。
3、A一定包含B,B一定包含A - 用隐式解析+无主引用解决
举例:国家一定包含首都,首都也一定在一个国家里
class Country {let name: Stringlet capitalCity: City!init(name: String, capitalName: String) {self.name = nameself.capitalCity = City(name: capitalName, country: self)}}class City {let name: Stringunowned let country: Countryinit(name: String, country: Country) {self.name = nameself.country = country}}
这里,Country的构造函数里,City要调用self,而只有Country的实例完全初始化结束后才能调用self。所以,capitialCity设为隐式可选类型,让他默认为nil,这样构造过程的第一阶段就可以不包括captialCity,就可以把self赋值给Country赋值给capittalCity了。
想详细看看构造过程的两个阶段,参照我之前写的构造过程文章,还不懂的话请留言。
这样设计的意义是:可以通过一条构造与巨还构造国家和首都两个实例,并且可以不用可选解析的方式来访问首都实例。
var country = Country(name: "Canada", capitalName: "Ottawa")println("\(country.name)'s capital city is called \(country.capitalCity.name)")
4 0
- IOS中解决ARC类实例间循环引用(Swfit)
- iOS中Block的引用循环问题 (ARC & non-ARC)
- iOS Block 中 循环引用的解决
- iOS解决循环引用
- [iOS]ARC下循环引用的问题
- [iOS]ARC下循环引用的问题
- [iOS]ARC下循环引用的问题
- [IOS]ARC下循环引用的问题
- [iOS]ARC下循环引用的问题
- [iOS]ARC下循环引用的问题
- [iOS]ARC下循环引用的问题
- [iOS]ARC下循环引用的问题
- 【读书笔记】iOS-ARC-Xcode检测循环引用
- 【读书笔记】iOS-ARC-循环引用-解决办法
- arc 和 非arc 中 block 的循环引用
- 在ios开发中,ARC的循环引用问题和解决办法
- iOS之block使用小结、在arc中使用block、如何防止循环引用
- iOS 解决block中self的循环引用问题
- C 知识点
- knitr包 R语言
- 判别模型 和 生成模型
- Unity3D LoadingScene
- 前端编程提高之旅(十四)----jquery DOM操作
- IOS中解决ARC类实例间循环引用(Swfit)
- UIkit 类图
- Unity3D 动态加载外部MovieTexture视频
- SMACK简介
- 在ListCtrl中插入图标(II)
- Xcode6 模拟器不显示键盘解决方案
- 关于XMPP MUC的一些感悟
- Oracle IMP用法研究
- visualvm监控远程机器上的Java程序