循环调用:
1.循环引用的问题
两个对象A、B,有可能会出现特殊情况:A中包含B的实例变量;B中也包含A的实例变量,如果这两个实例变量都是强引用(A有着B的实例变量所有权,B也有A的实例变量所有权),然后在两个对象销毁时,会出现A、B都不能正常销毁的情况。下面用代码来演示循环调用问题:

ClassA的头文件Class.h代码

  1. #import <Foundation/Foundation.h>
  2. //类的前向声明
  3. @class ClassB;
  4. //类的前向声明与包含头文件的区别?Q:
  5. @interface ClassA : NSObject
  6. //retain在ARC下面可以使用,但是最后使用strong
  7. @property(nonatomic,retain)ClassB *b;
  8. @end
ClassA的实现文件Class.m代码
  1. #import "ClassA.h"
  2. #import "ClassB.h"
  3. @implementation ClassA
  4. -(void)dealloc
  5. {
  6. NSLog(@"A的dealloc");
  7. [_b release];
  8. [super dealloc];
  9. }
  10. @end

ClassB的头文件ClassB.h代码:

  1. #import <Foundation/Foundation.h>
  2. @class ClassA;
  3. @interface ClassB : NSObject
  4. @property(nonatomic,retain)ClassA *a;
  5. @end

ClassB的实现文件ClassB.m代码:

  1. #import "ClassB.h"
  2. #import "ClassA.h"
  3. @implementation ClassB
  4. -(void)dealloc
  5. {
  6. NSLog(@"B的dealloc");
  7. [_a release];
  8. [super dealloc];
  9. }
  10. @end

接下来就是测试文件main.m代码:

  1. #import <Foundation/Foundation.h>
  2. #import "ClassA.h"
  3. #import "ClassB.h"
  4. int main(int argc, const char * argv[]) {
  5. @autoreleasepool {
  6. ClassA *a = [[ClassA alloc]init];
  7. ClassB *b = [[ClassB alloc]init];
  8. [a setB:b];
  9. [b setA:a];
  10. //获得所有权的是强引用
  11. /*因为对象a,对象b都是强引用,造成循环引用,无法正常释放。
  12. 解决方法:将其中一个改为弱引用。不获取对象所有权
  13. */
  14. [a release];
  15. [b release];
  16. }
  17. return 0;
  18. }

  细心地同学会发现,在ClassA和ClassB的头文件中@property的属性这是均为retain,这表明都是强引用会获得对象所有权,这样就会使程序循环调用,而无法正常释放,解决方法为将二者之一的属性改为弱引用,比如改为assign。这样就无法获得对象所有权,从而能顺利解决循环调用问题。

2.前向引用和#import包含的区别?

  一是import这两个被引用类的头文件,另一个是使用@class申明是类名,二者的区别:

  1). import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你;

  2). 在头文件中,一般只需要知道被引用的类的名称就可以了,不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称,而在类的实现部分,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。

  3). 在编译效率方面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次被引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用@class则不会。

  4). 如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。

  所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.

 
 

对象复制:

  1.创建一个新对象,新对象的内容和旧对象的内容是一样的。

  2.给现有的对象发送copy消息,就可以复制出新的对象。

  3.类中的对象类型实例变量,如果不想受外界影响,应该采用copy的方式复制出新的对象。

对象复制分为浅复制和深复制:

  浅复制:复制对象时,如果对象中包含对象类型的实例变量,只复制指针值,新对象中的对象类型实例变量和旧对象中的对象类型实例变量指的是同一个对象。

  深复制:复制对象时,如果对象中包含对象类型的实例变量,要对对象类型的实例变量也要做对象复制,新对象中的对象类型实例变量和旧对象中的对象类型实例变量指的是不同的对象。

  复制对象有两种copy和mutableCopy:

  1.copy用于不可变对象的复制;

  2.mutableCopy复制出来的是可变对象;

自动释放池使用的五种方式

方式一:

  1. @autoreleasepool{
  2. Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
  3. [book print];
  4. }

方式二:

  1. NSAutoreleasePool *pool = [NSAutoreleasePool new];
  2. Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
  3. [book print];
  4. [pool drain]; //等效于[pool release];

方式三:

  1. @autoreleasepool
  2. {
  3.   Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
  4.   [book print];
  5.   @autoreleasepool
  6.   {
  7.     Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
  8.     [book print];
  9.   }
  10. }

方式四

  1. @autoreleaspool
  2. {
  3.   for(int i = 0;i < 10000;i++)
  4.   {
  5.     @autoreleasepool
  6.     {
  7.       Book *book = [Book bookWithTitle:[NSString stringWithFormat:@“book%d”,i+1] andAuthor:[NSString stringWithFormat:@“author%d”,i+1] andPrice:20+i];
  8.       [book print];
  9.     }
  10.   }
  11. }

方式五:

  1. @autoreleasepool
  2. {
  3.   NSMutableString *str = [NSMutableString stringWithString:@“hello world”];
  4.   NSLog(@“%@“,str);
  5.   /*凡是不通过new、alloc、copy创建的对象都不拥有对象所有权,这种创建的对象会自动加入自动释放池,由自动释放池进行延迟释放*/
  6. }

  下面对自动释放池的使用进行了总结:

  1.在自动释放池结束时会给每个管理的对象发送一次release消息

  2.[book release]的作用是将对象加入自动释放池

  3.在OC的内置类(NSString、NSArray等)中提供的类方法创建的对象实例都是(延迟释放对象),也就是在对象创建完成后将对象加入自动释放池,这种对象不需要我们去发release消息释放。(方法五)

  4.自动释放池是可以嵌套使用的,对象在加入自动释放池时,选择离它最近的释放池,就近原则,(好聪明啊!都知道懒省事),目的是为了让延迟释放的对象,尽快得到释放,降低程序期间内存的占用。(方式3)

  5.当程序中出现大量创建延迟释放对象的代码时,最好给它加一个独立的自动释放池,保证这些对象在不使用时立刻释放掉(方法四)

 
 
 摘录部分(深复制和浅复制)
3.深复制和浅复制

浅 复 制:在复制操作时,对于被复制的对象的每一层复制都是指针复制。

深 复 制:在复制操作时,对于被复制的对象至少有一层复制是对象复制。

完全复制:在复制操作时,对于被复制的对象的每一层复制都是对象复制。

1在复制操作时,对于对象有n层是对象复制,我们可称作n级深复制,此处n应大于等于1。

2对于完全复制如何实现(目前通用的办法是:迭代法和归档),这里后续是否添加视情况而定,暂时不做讲解。

3、指针复制俗称指针拷贝,对象复制也俗称内容拷贝。

4、一般来讲,

浅层复制:复制引用对象的指针。

深层复制:复制引用对象内容。

这种定义在多层复制的时候,就显得模糊。所以本文定义与它并不矛盾。反而是对它的进一步理解和说明。           

retain:始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。

copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制,引用计数每次加一。始终返回一个不可变对象。

mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。

不可变对象:值发生改变,其内存首地址随之改变。

可变对象:无论值是否改变,其内存首地址都不随之改变。

引用计数:为了让使用者清楚的知道,该对象有多少个拥有者(即有多少个指针指向同一内存地址)。

OC_内存管理(二)对象复制、循环引用问题、自动释放池的更多相关文章

  1. OC中对象元素的引用计数 自动释放池的相关概念

    OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc]  view plaincopy 1. //   2. / ...

  2. objective-C 的内存管理之-自动释放池(autorelease pool)

    如果一个对象的生命周期显而易见,很容易就知道什么时候该new一个对象,什么时候不再需要使用,这种情况下,直接用手动的retain和release来判定其生死足矣.但是有些时候,想知道某个对象在什么时候 ...

  3. Python对象的循环引用问题

    目录 Python对象循环引用 循环引用垃圾回收算法 容器对象 生成容器对象 追踪容器对象 结束追踪容器对象 分代容器对象链表 何时执行循环引用垃圾回收 循环引用的垃圾回收 循环引用中的终结器 pyt ...

  4. OC学习篇之---数组对象的引用计数问题和自动释放池的概念

    之前一片文章中我们介绍了OC中的两个关键字@property和@synthesize的使用的使用: http://blog.csdn.net/jiangwei0910410003/article/de ...

  5. (20)Cocos2d-x中的引用计数(Reference Count)和自动释放池(AutoReleasePool)

    引用计数 引用计数是c/c++项目中一种古老的内存管理方式.当我8年前在研究一款名叫TCPMP的开源项目的时候,引用计数就已经有了. iOS SDK把这项计数封装到了NSAutoreleasePool ...

  6. OC 内存泄露 自动释放池

    花絮:看到下面的代码就想起这么一个调侃: 一个老程序员,功成名就,金盆洗手不在写代码后,决定练练书法.提笔思索良久后在纸上写下:Hello world! /********************** ...

  7. OC对象,自动释放池,OC与C语言的区别

    在C语言中,编程都是面向过程的编程,每一个代码块都严格按照从上至下的顺序执行,在代码块之间同样也是这样, 但是在OC中往往不是这样,OC和C++.java等语言一样,都是面向对象的编程语言,在代码的执 ...

  8. OC的内存管理(二)ARC

    指针: 指向内存的地址指针变量 存放地址的变量指针变量值 变量中存放的值(地址值)指针变量指向的内存单元值 内存地址指向的值1):强指针:默认的情况下,所有的指针都是强指针,关键字strong ):弱 ...

  9. JVM自动内存管理:对象判定和回收算法

    可回收对象的判断方法 1.引用计数算法 2.可达性分析算法 引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是 ...

随机推荐

  1. python django -4 模板

    模板介绍 作为Web框架,Django提供了模板,可以很便利的动态生成HTML 模版系统致力于表达外观,而不是程序逻辑 模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视 ...

  2. Java NIO(2):缓冲区基础

    缓冲区(Buffer)对象是面向块的I/O的基础,也是NIO的核心对象之一.在NIO中每一次I/O操作都离不开Buffer,每一次的读和写都是针对Buffer操作的.Buffer在实现上本质是一个数组 ...

  3. hdu 4576(概率dp+滚动数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4576 思路:由于每次从某一位置到达另一位置的概率为0.5,因此我们用dp[i][j]表示第i次操作落在 ...

  4. go语言递归创建目录

    import ( "fmt" "os" ) func main() { //创建C:/temp/log文件夹 // err := os.MkdirAll(&qu ...

  5. 转:: 刺鸟:用python来开发webgame服务端(5)

    来源:http://ciniao.me/article.php?id=19 --------------- 刺鸟原创文章,转载请注明出处    在前面的文章中,我们已经开始了不少逻辑功能的开发,在这期 ...

  6. K-th Number(主席树)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 59327   Accepted: 20660 Ca ...

  7. js 自学,云知梦知识 点理论

    一.第1章(1--4) 何为js特效 1.定义事件(触发时机+行为) 2.触发事件(行为发生) 3.事件发生是具有重复性   js是基本对象的语言. 面向对像编程 1.如何获得该对象 2.如何 调用该 ...

  8. Python迭代器包itertools(转)

    原文:http://www.cnblogs.com/vamei/p/3174796.html 作者:Vamei 在循环对象和函数对象中,我们了解了循环器(iterator)的功能.循环器是对象的容器, ...

  9. 如何在Pycharm设置ES6语法环境

    首先 如果不进行相关设置就刚ES6 语法的话,会出现下面提示性错误(运行还是能正常出效果的): (let 飘红, 这只是其中之一, 其他语法也会飘红) 接着,就是解决问题: 首先打开设置: 接着找到下 ...

  10. python面试题(三)

    1 一行代码实现9*9乘法表 print ("\n".join("\t".join(["%s*%s=%s" %(x,y,x*y) for y ...