OC_内存管理(二)对象复制、循环引用问题、自动释放池
ClassA的头文件Class.h代码
- #import <Foundation/Foundation.h>
- //类的前向声明
- @class ClassB;
- //类的前向声明与包含头文件的区别?Q:
- @interface ClassA : NSObject
- //retain在ARC下面可以使用,但是最后使用strong
- @property(nonatomic,retain)ClassB *b;
- @end
- #import "ClassA.h"
- #import "ClassB.h"
- @implementation ClassA
- -(void)dealloc
- {
- NSLog(@"A的dealloc");
- [_b release];
- [super dealloc];
- }
- @end
ClassB的头文件ClassB.h代码:
- #import <Foundation/Foundation.h>
- @class ClassA;
- @interface ClassB : NSObject
- @property(nonatomic,retain)ClassA *a;
- @end
ClassB的实现文件ClassB.m代码:
- #import "ClassB.h"
- #import "ClassA.h"
- @implementation ClassB
- -(void)dealloc
- {
- NSLog(@"B的dealloc");
- [_a release];
- [super dealloc];
- }
- @end
接下来就是测试文件main.m代码:
- #import <Foundation/Foundation.h>
- #import "ClassA.h"
- #import "ClassB.h"
- int main(int argc, const char * argv[]) {
- @autoreleasepool {
- ClassA *a = [[ClassA alloc]init];
- ClassB *b = [[ClassB alloc]init];
- [a setB:b];
- [b setA:a];
- //获得所有权的是强引用
- /*因为对象a,对象b都是强引用,造成循环引用,无法正常释放。
- 解决方法:将其中一个改为弱引用。不获取对象所有权
- */
- [a release];
- [b release];
- }
- return 0;
- }
细心地同学会发现,在ClassA和ClassB的头文件中@property的属性这是均为retain,这表明都是强引用会获得对象所有权,这样就会使程序循环调用,而无法正常释放,解决方法为将二者之一的属性改为弱引用,比如改为assign。这样就无法获得对象所有权,从而能顺利解决循环调用问题。
一是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:
2.mutableCopy复制出来的是可变对象;
自动释放池使用的五种方式
方式一:
- @autoreleasepool{
- Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
- [book print];
- }
方式二:
- NSAutoreleasePool *pool = [NSAutoreleasePool new];
- Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
- [book print];
- [pool drain]; //等效于[pool release];
方式三:
- @autoreleasepool
- {
- Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
- [book print];
- @autoreleasepool
- {
- Book *book = [Book alloc]initWithTitle:@“Object-C” andAuthor:@“Jobs” andPrice:23.90];
- [book print];
- }
- }
方式四
- @autoreleaspool
- {
- for(int i = 0;i < 10000;i++)
- {
- @autoreleasepool
- {
- Book *book = [Book bookWithTitle:[NSString stringWithFormat:@“book%d”,i+1] andAuthor:[NSString stringWithFormat:@“author%d”,i+1] andPrice:20+i];
- [book print];
- }
- }
- }
方式五:
- @autoreleasepool
- {
- NSMutableString *str = [NSMutableString stringWithString:@“hello world”];
- NSLog(@“%@“,str);
- /*凡是不通过new、alloc、copy创建的对象都不拥有对象所有权,这种创建的对象会自动加入自动释放池,由自动释放池进行延迟释放*/
- }
下面对自动释放池的使用进行了总结:
1.在自动释放池结束时会给每个管理的对象发送一次release消息
2.[book release]的作用是将对象加入自动释放池
3.在OC的内置类(NSString、NSArray等)中提供的类方法创建的对象实例都是(延迟释放对象),也就是在对象创建完成后将对象加入自动释放池,这种对象不需要我们去发release消息释放。(方法五)
4.自动释放池是可以嵌套使用的,对象在加入自动释放池时,选择离它最近的释放池,就近原则,(好聪明啊!都知道懒省事),目的是为了让延迟释放的对象,尽快得到释放,降低程序期间内存的占用。(方式3)
5.当程序中出现大量创建延迟释放对象的代码时,最好给它加一个独立的自动释放池,保证这些对象在不使用时立刻释放掉(方法四)
浅 复 制:在复制操作时,对于被复制的对象的每一层复制都是指针复制。
深 复 制:在复制操作时,对于被复制的对象至少有一层复制是对象复制。
完全复制:在复制操作时,对于被复制的对象的每一层复制都是对象复制。
1、在复制操作时,对于对象有n层是对象复制,我们可称作n级深复制,此处n应大于等于1。
2、对于完全复制如何实现(目前通用的办法是:迭代法和归档),这里后续是否添加视情况而定,暂时不做讲解。
3、指针复制俗称指针拷贝,对象复制也俗称内容拷贝。
4、一般来讲,
浅层复制:复制引用对象的指针。
深层复制:复制引用对象内容。
retain:始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。
copy:对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制,引用计数每次加一。始终返回一个不可变对象。
mutableCopy:始终是深复制,引用计数不改变。始终返回一个可变对象。
不可变对象:值发生改变,其内存首地址随之改变。
可变对象:无论值是否改变,其内存首地址都不随之改变。
引用计数:为了让使用者清楚的知道,该对象有多少个拥有者(即有多少个指针指向同一内存地址)。
OC_内存管理(二)对象复制、循环引用问题、自动释放池的更多相关文章
- OC中对象元素的引用计数 自动释放池的相关概念
OC中数组对象在是如何处理对象元素的引用计数问题的,同时介绍一下自动释放池的相关概念 一.数组对象是如何处理对象元素的引用计数问题[objc] view plaincopy 1. // 2. / ...
- objective-C 的内存管理之-自动释放池(autorelease pool)
如果一个对象的生命周期显而易见,很容易就知道什么时候该new一个对象,什么时候不再需要使用,这种情况下,直接用手动的retain和release来判定其生死足矣.但是有些时候,想知道某个对象在什么时候 ...
- Python对象的循环引用问题
目录 Python对象循环引用 循环引用垃圾回收算法 容器对象 生成容器对象 追踪容器对象 结束追踪容器对象 分代容器对象链表 何时执行循环引用垃圾回收 循环引用的垃圾回收 循环引用中的终结器 pyt ...
- OC学习篇之---数组对象的引用计数问题和自动释放池的概念
之前一片文章中我们介绍了OC中的两个关键字@property和@synthesize的使用的使用: http://blog.csdn.net/jiangwei0910410003/article/de ...
- (20)Cocos2d-x中的引用计数(Reference Count)和自动释放池(AutoReleasePool)
引用计数 引用计数是c/c++项目中一种古老的内存管理方式.当我8年前在研究一款名叫TCPMP的开源项目的时候,引用计数就已经有了. iOS SDK把这项计数封装到了NSAutoreleasePool ...
- OC 内存泄露 自动释放池
花絮:看到下面的代码就想起这么一个调侃: 一个老程序员,功成名就,金盆洗手不在写代码后,决定练练书法.提笔思索良久后在纸上写下:Hello world! /********************** ...
- OC对象,自动释放池,OC与C语言的区别
在C语言中,编程都是面向过程的编程,每一个代码块都严格按照从上至下的顺序执行,在代码块之间同样也是这样, 但是在OC中往往不是这样,OC和C++.java等语言一样,都是面向对象的编程语言,在代码的执 ...
- OC的内存管理(二)ARC
指针: 指向内存的地址指针变量 存放地址的变量指针变量值 变量中存放的值(地址值)指针变量指向的内存单元值 内存地址指向的值1):强指针:默认的情况下,所有的指针都是强指针,关键字strong ):弱 ...
- JVM自动内存管理:对象判定和回收算法
可回收对象的判断方法 1.引用计数算法 2.可达性分析算法 引用计数算法 给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器为0的对象就是 ...
随机推荐
- asp.net中TextBox只能输入数字的最简洁的两种方法
如下TextBox <asp:textboxonkeypress="isnum()"id="TextBox1"runat="server&quo ...
- poj 2516(拆点+最小权匹配)
题目链接:http://poj.org/problem?id=2516 思路:考虑某种货物,由于某个订货商可能接受来自不同地区的货物,而某一地区的货物也可能送给不同的订货商,显然不能直接进行匹配,必须 ...
- react手记(componentWillMount,componentDidMount等)
生命周期componentWillMount 组件出现前 就是dom还没有渲染到html文档里面componentDidMount 组件渲染完成 已经出现在dom文档里可以再各个周期实现特定的操作 生 ...
- Tomcat虚拟目录
x先来看一段server.xml文件里的配置: <Host appBase="" autoDeploy="true" debug="0" ...
- 使用jsx语法环境搭建
1.安装nodejs.nodejs安装后会自带npm,可以用 npm -v 进行查看版本.使用 npm install npm -g 更新文档. 2.创建自己项目,在你的项目路径下执行npm init ...
- vfptr(2)
//i_vptr struct i_vptr { ; }; //vptr.h #include "i_vptr.h" #include <iostream> class ...
- hdu2587(递推)
目前做过的最纠结的一道递推题. 情况比较多,比较复杂... 这题最主要的还是要推出当m=2 时和m>2时,用什么方法最优. 给个数据 n=3,m=2 需要48 n=3,m=3 需要81 如果 ...
- 类 String、StringBuffer、StringBuilder
类 String String 类代表字符串.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现.字符串是常量:它们的值在创建之后不能更改.字符串缓冲区支持 ...
- spring web中完成单元测试
对于在springweb总完单元测试,之前找过些资料,摸索了很久,记录下最终自己使用的方法 1,创建测试类,创建测试资源文件夹 src/test/resources/WEB_INFO/conf 将工程 ...
- ACM中使用 JAVA v2. 1
ACM中使用JAVA v2.1 严明超 (Blog:mingchaoyan.blogbus.com Email:mingchaoyan@gmail.com) 0.前 言 文前声明:本文只谈java用于 ...