这段时间在研究关于ARC得循环引用导致变量不能释放,在此先介绍一本书英文书:

《Pro Multithreading and Memory Management for iOS and OS X with ARC, Grand Central Dispatch, and Blocks》

(《iOS与OS X多线程和内存管理》)

建议读英文原版,中文版看的我稀里糊涂的,后来被迫去看原版.这本书介绍了关于ARC的自动引用机制,这里的机制类似:当C语言的局部变量离开他的作用域之后就会被清除,这里的ARC也类似是这样的原理,如下面的代码一样,当离开{}之后obj会被nil。默认id是强指针

{
/*
* You create an object and have ownership. */
id __strong obj = [[NSObject alloc] init];
/*
* The variable obj is qualified with __strong.
* Which means, it has ownership of the object. */
}
/*
* Leaving the scope of variable obj, its strong reference disappears.
* The object is released automatically.
* Because no one has ownership, the object is disposed of.
*/

不过有一种情况会导致在{}内的变量再离开作用域之后不会释放,这就是循环引用,下面我先贴一份没有循环引用的代码

//Test Class
@interface Test : NSObject
@property (nonatomic) id obj;
- (void) setObj:(id)obj;
@end
@implementation Test
- (void) setObj:(id)obj{
_obj = obj;
}
@end //Use Test Class
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
id test0 = [[Test alloc]init];
id test1 = [[Test alloc]init]; self.t0 = test0;
self.t1 = test1;
} - (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated]; NSLog(@"test0 is %@",self.t0);
NSLog(@"test1 is %@",self.t1);
NSLog(@"test0 obj is %@",self.t0.obj);
NSLog(@"test1 obj is %@",self.t1.obj);
NSLog(@"viewDidApperar!");
}
/* 这里的输出结果:
2014-11-18 11:39:31.654 circular[27065:60b] test0 is (null)
2014-11-18 11:39:31.654 circular[27065:60b] test1 is (null)
2014-11-18 11:39:31.655 circular[27065:60b] test0 obj is (null)
2014-11-18 11:39:31.655 circular[27065:60b] test1 obj is (null)
2014-11-18 11:39:31.655 circular[27065:60b] viewDidApperar!
*/

/*

  • *  Leaving the scope of variable test0, its strong reference disappears.

  • *  object A is released automatically. *

  • *  Leaving the scope of variable test1, its strong reference disappears.

  • *  object B is released automatically.

    *

  • *  At this moment, obj_ of object B has a strong reference to object A. *

  • *  At this moment, obj_ of object A has a strong reference to object B. *

  • *  memory leaked!! */

 

现在我贴一下存在循环引用的代码,这个时候局部变量的强指针相互引用,这里我们可以看见Test0的obj指向Test1,而Test1的obj指向Test0,导致释放不了.

//Test Class
@interface Test : NSObject
@property (nonatomic) id obj;
- (void) setObj:(id)obj;
@end
@implementation Test
- (void) setObj:(id)obj{
_obj = obj;
}
@end //Use Test Class
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
id test0 = [[Test alloc]init];
id test1 = [[Test alloc]init];
[test0 setObj:test1];
[test1 setObj:test0];
self.t0 = test0;
self.t1 = test1;
} - (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated]; NSLog(@"test0 is %@",self.t0);
NSLog(@"test1 is %@",self.t1);
NSLog(@"test0 obj is %@",self.t0.obj);
NSLog(@"test1 obj is %@",self.t1.obj);
NSLog(@"viewDidApperar!");
} /*这里的输出结果:
2014-11-18 11:42:35.555 circular[27654:60b] test0 is <Test: 0x8c8fe20>
2014-11-18 11:42:35.556 circular[27654:60b] test1 is <Test: 0x8cf7c20>
2014-11-18 11:42:35.556 circular[27654:60b] test0 obj is <Test: 0x8cf7c20>
2014-11-18 11:42:35.556 circular[27654:60b] test1 obj is <Test: 0x8c8fe20>
2014-11-18 11:42:35.558 circular[27654:60b] viewDidApperar!
*/

一般的解决办法就是weak obj,代码如下:

//Test Class
@interface Test : NSObject
@property (nonatomic,weak) id obj;
- (void) setObj:(id)obj;
@end
@implementation Test
- (void) setObj:(id)obj{
_obj = obj;
}
@end //Use Test Class
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
id test0 = [[Test alloc]init];
id test1 = [[Test alloc]init];
[test0 setObj:test1];
[test1 setObj:test0];
self.t0 = test0;
self.t1 = test1;
} - (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated]; NSLog(@"test0 is %@",self.t0);
NSLog(@"test1 is %@",self.t1);
NSLog(@"test0 obj is %@",self.t0.obj);
NSLog(@"test1 obj is %@",self.t1.obj);
NSLog(@"viewDidApperar!");
} /*这里的输出结果:
2014-11-18 11:46:19.803 circular[28360:60b] test0 is (null)
2014-11-18 11:46:19.804 circular[28360:60b] test1 is (null)
2014-11-18 11:46:19.804 circular[28360:60b] test0 obj is (null)
2014-11-18 11:46:19.805 circular[28360:60b] test1 obj is (null)
2014-11-18 11:46:19.805 circular[28360:60b] viewDidApperar!
*/

那么我们现在来了解一下为什么使用weak之后就会解除循环引用呢?

当我们直接写  id __weak obj = [[NSObject alloc] init];

会提示警告:因为使用了weak,所以obj并不持有该对象,那么[[NSObject alloc] init]被创建之后没有人持有它,那么它就会被释放,所以这里应该修改成,当执行{}之后 obj0 和 obj1 都会被释放,因为当obj0被释放之后,obj1会变成nil因为weak引用不持有对象,当引用对象的强指针消失时,weak声明的指针也会自动null

{
/*
* You create an object and have ownership. */
id __strong obj0 = [[NSObject alloc] init];
/*
* The variable obj0 is qualified with __strong.
* Which means, it has ownership of the object. */
id __weak obj1 = obj0;
/*
* variable obj1 has a weak reference of the created object */
} /*
* Leaving the scope of variable obj0, its strong reference disappears.
* The object is released automatically.
* Because no one has ownership, the object is discarded. */

那么下面这个例子就说明了weak会自动null

id __weak obj1; //__strong ,__weak 声明的变量会自动设置成为nil,这里等同于 id __weak obj1 = nil; 
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A: %@", obj1);
}
NSLog(@"B: %@", obj1);
The result is:
A: <NSObject: 0x753e180> B: (null)

浅谈 关于ARC循环引用得问题的更多相关文章

  1. 浅谈Java中的引用

    在Java语言中,引用是指,某一个数据,代表的是另外一块内存的的起始地址,那么我们就称这个数据为引用. 在JVM中,GC回收的大致准则,是认定如果不能从根节点,根据引用的不断传递,最终指向到一块内存区 ...

  2. 浅谈ThreadPool 线程池(引用)

    出自:http://www.cnblogs.com/xugang/archive/2010/04/20/1716042.html 浅谈ThreadPool 线程池 相关概念: 线程池可以看做容纳线程的 ...

  3. 浅谈Spring解决循环依赖的三种方式

    引言:循环依赖就是N个类中循环嵌套引用,如果在日常开发中我们用new 对象的方式发生这种循环依赖的话程序会在运行时一直循环调用,直至内存溢出报错.下面说一下Spring是如果解决循环依赖的. 第一种: ...

  4. JS浅谈原始值与引用值操作

    值的操作分为三大类:复制,传递,比较 一:复制 原始值 let a = 10; let b = a; 注释:2018-7-30 17:33:49 1 原始类型的值都是存放在栈内存当中,所以他们的赋值操 ...

  5. 浅谈js for循环输出i为同一值的问题

    问题再现 ​ 最近开发中遇到一个问题,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5. <html> <head> <meta http- ...

  6. 浅谈js for循环输出i为同一值的问题(闭包解决)

    1.最近开发中遇到一个问题,为什么每次输出都是5,而不是点击每个p,就alert出对应的1,2,3,4,5. <html> <head> <meta http-equiv ...

  7. Spring5.0源码学习系列之浅谈循环依赖问题

    前言介绍 附录:Spring源码学习专栏 在上一章的学习中,我们对Bean的创建有了一个粗略的了解,接着本文浅谈Spring循环依赖问题,这是一个面试比较常见的问题 1.什么是循环依赖? 所谓的循环依 ...

  8. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  9. block使用小结、在arc中使用block、如何防止循环引用

    引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题: [小测试]你真的知道blocks在Objective-C中是怎么工作的吗 ...

随机推荐

  1. nginx upstream的几种配置方式

    nginx 的upstream目前支持4种方式的分配 1.轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器 ,如果后端服务器down掉,能自动剔除. 2.weight指定轮询几率,weigh ...

  2. 问题:HttpContext.Current.Session;结果:Session与HttpContext.Current.Session到底有什么区别呢?

    我在做练习的时候遇到了这样一个问题,在母版页页面中写入登录和密码修改的js代码,在登录的方法中写 入 HttpContext.Current.Session.Add("UserPwd&quo ...

  3. linux中安装sqlmap

    wget https://codeload.github.com/sqlmapproject/sqlmap/legacy.tar.gz/master //下载sqlmap tar zxvf maste ...

  4. MSSQL 日期查询 包含NULL值

    方一: 以下做法保证数据里面没有NULL值 '') '') '') '') exec sp_executesql N'select ide_code as ''系统编号'',name as ''申请专 ...

  5. 使用HttpClient进行Post通信

    ---------------siwuxie095                         首先到 Apache官网 下载相关的库文件     Apache官网:http://www.apac ...

  6. [转]PHP 面试问哪些问题可以比较准确的反映出应聘者的开发水平?

    基础题 场景: 你入职了一家新公司. 上班第一天,接待人给你安排好了座位,然后拉过来一台没拆封的新电脑. 你把电脑连接好之后,按下电源.... 好吧,这真是一台新电脑,里边竟然内置了个DOS系统!! ...

  7. Selenium二次封装-Python版本

    from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait from seleni ...

  8. IO流对文件的读取操作

    /*1. 在当前项目的根目录下有一个名为“info.txt”的文件,里面存放的内容如下(可手动创建录入,不需要使用IO流): 2. 利用IO流的知识读取info.txt文件的内容, 在控制台上打印大写 ...

  9. 仿射变换详解 warpAffine

    转自 http://www.cnblogs.com/dupuleng/articles/4055020.html 博客园 首页 新随笔 联系 管理 订阅 随笔- 1  文章- 185  评论- 14  ...

  10. apt-get默认下载路径

    备忘: Ubuntu中apt-get下载的安装包都在哪里呢? 在/var/cache/apt/archives里,里边的安装包可以取出来以备后用.