swift 循环强引用

Swift使用自动引用计数(ARC)来管理应用程序的内存使用。在大多是情况下,并不需要考虑内存的管理。当实例不再需要的时候,ARC会自动释放这些实例所使用的内存。
但ARC并不是绝对安全的。下面两种情况会发生内存泄露。

1,类实例之间的循环强引用
两个类实例都有一个强引用指向对方,这样的情况就是强引用循环,从而导致内存泄露。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class  Teacher  {
     var  tName :  String
     var  student :  Student ?
     
     init (name: String ){
         tName = name
         println ( "老师\(tName)实例初始化完成" )
     }
     
     deinit{
         println ( "老师\(tName)实例反初始化完成" )
     }
}
 
class  Student  {
     var  sName :  String
     var  teacher :  Teacher ?
     
     init (name: String ){
         sName = name
         println ( "学生\(sName)实例初始化完成" )
     }
     
     deinit{
         println ( "学生\(sName)实例反初始化完成" )
     }
}
 
//测试开始
var  teacher: Teacher ?
var  student: Student ?
teacher =  Teacher (name:  "李老师" )
student =  Student (name:  "刘同学" )
teacher!.student = student
student!.teacher = teacher       
teacher =  nil
student =  nil
 
//测试结果(deinit未调用,则内存泄露)
老师李老师实例初始化完成
学生刘同学实例初始化完成

解决办法:使用弱引用
只需要将上述例子Teacher类的student变量加上关键字weak,或者将Student类的teacher变量加上关键字weak。
当A类中包含有B类的弱引用的实例,同时,B类中存在A的强引用实例时,如果A释放,也不会影响B的释放。但A的内存回收要等到B的实例释放后才可以回收。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class  Teacher  {
     var  tName :  String
     weak  var  student :  Student ?
     
     init (name: String ){
         tName = name
         println ( "老师\(tName)实例初始化完成" )
     }
     
     deinit{
         println ( "老师\(tName)实例反初始化完成" )
     }
}
 
class  Student  {
     var  sName :  String
     var  teacher :  Teacher ?
     
     init (name: String ){
         sName = name
         println ( "学生\(sName)实例初始化完成" )
     }
     
     deinit{
         println ( "学生\(sName)实例反初始化完成" )
     }
}

2,闭包引起的循环强引用 
将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了实例,也会发生强引用循环。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class  JsonElement {
     let  name: String
     let  jValue: String ?
     
     lazy  var  asJson:() ->  String  = {
         if  let  text =  self .jValue {
             return  "\(self.name):\(text)"
         } else {
             return  "text is nil"
         }
     }
     
     init (name: String , text: String ){
         self .name = name
         self .jValue = text
         println ( "初始化闭包" )
     }
     
     deinit{
         println ( "闭包释放" )
     }
}
 
//开始测试
var  p: JsonElement ? =  JsonElement (name:  "p" , text:  "hangge.com" )
println (p!.asJson())
p =  nil
 
//测试结果(deinit未调用,则内存泄露)
初始化闭包
p:hangge.com

解决办法:使用闭包捕获列表
当闭包和实例之间总是引用对方并且同时释放时,定义闭包捕获列表为无主引用。但捕获引用可能为nil时,定义捕获列表为弱引用。弱引用通常是可选类型,并且在实例释放后被设置为nil。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  JsonElement {
     let  name: String
     let  jValue: String ?
     
     lazy  var  asJson:() ->  String  = {
         [ unowned  self in  //使用无主引用来解决强引用循环
         if  let  text =  self .jValue {
             return  "\(self.name):\(text)"
         } else {
             return  "text is nil"
         }
     }
     
     init (name: String , text: String ){
         self .name = name
         self .jValue = text
         println ( "初始化闭包" )
     }
     
     deinit{
         println ( "闭包释放" )
     }
}

原文出自: www.hangge.com   转载请保留原文链接: http://www.hangge.com/blog/cache/detail_742.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值