内存管理的思考方式,ARC中weak、strong的区别,循环引用

文章目录

  • 内存管理的思考方式
  • ARC中weak、strong的区别
  • 循环引用
准备好了吗?
  • 1.内存管理的思考方式

先简单说说内存管理
iOS中有两种类型的变量
第一种 值类型 : int , float ,double,Bool
第二种 引用类型 : OC对象

分别有下面几个存储区域
1)全局区和静态区:全局变量,静态变量
2)栈区:一些自动变量和
3)堆区:对象
4)常量区:各种不能被改变的常量

下面看看iOS如何管理内存的
第一个例子 “自己生成并持有对象”

id obj = [[NSObject alloc]init];
//(自己生成并持有对象) NSObject类生成的对象A(假如叫做A)被obj持有
[obj release];
//释放A

这里有个定义,用alloc/new/copy/mutableCopy方法生成的对象为自己生成,其他则为非自己生成。

第二个例子 “非自己生成对象被自己持有”

{
id obj = [NSMutableArray array];
/*[NSMutableArray array]生成的对象B(假如叫做B),但不被obj持有  
这时直接调用[obj release];是不行的,会导致程序崩溃*/
[obj retain];
//此时持有B
[obj release];
//释放B
}

引用计数式内存管理分为以下四种

  • 自己生成的对象,自己持有
  • 非自己生成的对象,自己持有
  • 自己持有的对象不再需要时释放
  • 非自己持有的对象无法释放
  • 2.ARC中weak、strong的区别

ARC为自动引用计数,从这以后,开发者就不用显式地调用retain、release这些方法了,因此会自动调用。
简单来说
strong(强引用)修饰的对象被赋值时会对其引用计数会加1,而weak(弱引用)修饰的对象被赋值时对其引用计数不做改变

像这样的代码

//id __strong就是被strong修饰的id类,其实id默认也是有__strong
//id __weak就是被weak修饰的id类
{
	id __strong obj_strong = [[NSObject alloc]init];
	//NSObject类生成的对象A(假如叫做A)被obj_strong持有,A的引用计数加1,以前是0,现在是1,因为被强引用
    id __weak obj_weak = [[NSObject alloc]init];
     /* NSObject类生成的对象B(假如叫做B)被obj_weak持有,由于obj_weak是弱引用,  
     此时B被遗弃。编译器此时也会抛出警告:  
    Assigning retained object to weak variable; object will be released after assignment,  
    意思就是“将保留对象分配给弱变量; 对象将在分配后释放”。
    */
}
/*到这里,obj_strong超出了它的作用域,释放所有的强引用,这时就释放了对对象A的强引用  
对象A引用计数由1变为0,对象A被释放。*/

那么weak修饰的对象就没办法持有对象了吗,答案是否定的,可能你也想到,weak不能使对象引用计数发生变化,使原本引用计数为0的对象因此被抛弃,但weak可以持有引用计数为不为0的弱引用,并不会造成对象被抛弃,还是看代码吧

{
	id __strong obj_strong = [[NSObject alloc]init]; 
现在是1,因为被强引用*/
	id __weak obj_weak = obj_strong; 
	//obj_weak持有对象的弱引用,引用计数不发生变化,还为1
}
/*到这里,obj_strong超出了它的作用域,释放所有的强引用,这时就释放了对对象A的强
引用,  
对象A引用计数由1变为0,对象A被释放。obj_weak超出它的作用域,弱引用失效。*/

这样就使weak修饰的对象也能正常持有对象了

趁热打铁,再看一个例子

id __weak obj_weak = nil;
{
	id __strong obj_strong = [[NSObject alloc]init]; 
	/*NSObject类生成的对象A(假如叫做A)被obj_strong持有,A的引用计数加1,  
	以前是0,现在是1,因为被强引用*/
	obj_weak = obj_strong; 
	//obj_weak持有对象的弱引用,引用计数不发生变化,还为1
}
/*到这里,obj_strong超出了它的作用域,释放所有的强引用,这时就释放了对对象A的强引用,
对象A引用计数由1变为0,对象A被释放。obj_weak并超出它的作用域,弱引用还在,不过对象被释放掉了,
弱引用则自动失效且obj_weak被置为nil,以前是对对象A的弱引用。*/

那么到这里,我们可以对strong、weak有一些概念

strong
如果对象是“狗”,strong可以类比为“栓狗的绳子”,当狗被绳子拴着,即被strong修饰的对象持有,一根绳子代表引用计数为1,N根绳子代表引用计数为N,当strong修饰的对象超出其作用域会取消所有的强引用,即收回拴狗的绳子,当拴狗的绳子为0时,狗就跑了,即对象被释放了。

weak
如果对象是“狗”,weak可以类比为“小孩”,weak对对象的弱引用相当于“小孩看狗”,当狗不在了,即对象被释放,即使小孩还想看狗,即还没有超出自己的作用域,可狗确实是没有了,小孩则会离开,即weak对象被置为nil。

  • 3.循环引用
@interface  Text : NSObject
@property(strong) id  obj;
@end
- (UILabel *)setObj:(UILabel *)obj
 {	
  _obj = obj;
 }

 以下为循环引用
 {
    Text text1 = [[Text alloc]init];
	/*假设[[Text alloc]init]生成的对象叫做对象A,则text1持有A的强引用,
	对象A引用计数为1
	*/
    Text text2 = [[Text alloc]init];
	 /*假设[[Text alloc]init]生成的对象叫做对象B,则text2持有B的强引用,
	 对象B引用计数为1
	*/
	[text1 setObj:text2];
	/*text1(即对象A)的属性_obj持有对text2(即对象B)的强引用
	 对象B引用计数为2
	 此时,持有对象B强引用的有text2和text1的属性obj
	 */
	 
	 [text2 setObj:text1];
	 /*text2(即对象B)的属性_obj持有对text1(即对象A)的强引用
	 对象A引用计数为2
	 此时,持有对象A强引用的有text1和text2的属性obj
	 */
}
/*由于text1变量超出其作用域,强引用失效,即对对象A的强引用失效,对象A的引用计数为1
	由于text2变量超出其作用域,强引用失效,即对对象B的强引用失效,对象B的引用计数为1

此时对象A的强引用还有text2(即对象B)的属性obj,无法释放对象A
	
	对象B的强引用还有text1(即对象A)的属性obj,无法释放对象B
		
	由于循环引用	发生内存泄漏

这只是一个场景,发生循环引用的场景有很多,不过实质都是两个对象间的相互引用,导致相互释放,一直占用着内存。

这时,我们刚才学习的weak便可以发挥作用了

@interface  Text : NSObject
//我们把刚才的属性修饰符由strong改为weak
@property (weak)id  obj;
@end

- (UILabel *)setObj:(UILabel *)obj
 {	
  _obj = obj;
 }

 {
    Text text1 = [[Text alloc]init];
	//假设[[Text alloc]init]生成的对象叫做对象A,则text1持有A的强引用,对象A引用计数为1
    Text text2 = [[Text alloc]init];
	 //假设[[Text alloc]init]生成的对象叫做对象B,则text2持有B的强引用,对象B引用计数为1
	[text1 setObj:text2];
	/*text1(即对象A)的属性obj持有对text2(即对象B)的弱引用,对象B引用计数为1
	 此时,持有对象B强引用的有text2和text1的属性obj
	 */
	 
	 [text2 setObj:text1];
	 /*text2(即对象B)的属性obj持有对text1(即对象A)的弱引用,对象A引用计数为1
	 此时,持有对象A强引用的有text1和text2的属性obj
	 */
}
	/*由于text1变量超出其作用域,强引用失效,即对对象A的强引用失效,对象A的引用计数为0,对象A被释放,因此text2的属性obj对A的弱引用消失,即置为nil
	由于text2变量超出其作用域,强引用失效,即对对象B的强引用失效,对象B的引用计数为0,对象B被释放
	没有发生循环引用,问题被解决
	*/
	



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值