码迷,mamicode.com
首页 > 其他好文 > 详细

【Objective-C学习记录】第二十八天

时间:2015-12-29 21:10:46      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:

iOS内存管理的方式是引用计数机制,分为MRC(人工引用计数)和ARC(自动引用计数)。

引用计数管理内存的理念是:通过控制内存或者对象的引用来实现生成、持有、释放、销毁对象的操作。

如果增加的次数大于减少的次数,会造成内存泄露;

如果减少的次数大于增加的次数,会造成过度释放;

如果增加的次数等于减少的次数,还继续访问,会造成野指针。

1.生成:对象的引用计数从0到1

2.持有:增加一个引用,让对象的引用计数加1

3.释放:减少一个引用,让对象的引用计数加1

4.销毁:当对象的引用计数到0时(事实上并不会为0,后面会解释),系统就会回收这个内存空间

当这块空间被系统回收之后,就不能通过指针去访问这块空间了,容易造成野指针。

注意!引用计数的概念只存在于堆区域,针对堆区的对象。

retainCount方法

可以通过改方法获取对象的引用计数的值,返回值是NSUInteger。

1.生成

   + (instancetype)alloc;在堆区域开辟一块内存空间,释放对象,并且将内存清零,同时将此对象的引用计数变为1,是从0到1的过程。

1 Hero *hero = [[Hero alloc] init];//该过程为hero对象开辟了内存空间,引用计数加1

需要注意的是,直接赋值引用计数不会增加,如下:

1 Hero *am = hero//不会引起hero对象引用计数加1

2.持有

   retain;让对象的引用计数加1。

1 [hero retain];//此时hero的引用计数为2
2 [am retain];//此时hero/am的引用计数为3

3.释放

   A.release;让对象的引用计数减1,而且是立即减1。

1 [hero release];//hero的引用计数为2
2 [hero release];//hero的引用计数为1
3 [hero release];//hero的引用计数为1

需要注意的是,在对hero对象进行连续三次释放操作后,我们在XCode可以通过retainCount方法查看hero的引用计数的值,结果发现并不是我们所期望的0,这是因为系统内部引用计数值没有0,0只是人与人直接方便交流和理解而引人的一个数,但从本质上来说,该对象已经被释放了,如果再去访问hero对象有可能造成野指针(被回收的内存空间被其他指针或变量占用后,再次通过原指针去访问该内存)。

即引用计数值最小是1,没有0。

   B.autorelease;此方法也是让对象的引用计数减1,不过区别于release,并不是立即减1,而是在未来的某个时刻,触发减1操作。该操作与自动释放池相关。

   自动释放池(autoreleasepool)

   自动释放池是一个容器,来记录池子内部对象接收到的autorelease消息,哪个对象接收,接收了几次,谁先接收,谁后接收,当池子释放时,就会根据这些记录的信息来进行减1操作。

   需要注意的是,自动释放池与栈区类似,遵循先进后出即先开辟空间的后被进行减1操作。

1 Hero *sf = [[Hero alloc] init];
2 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
3 [hero autorelease];
4 [am autorelease];
5 [sf autorelease];
6 [pool release];//该语句执行时,会对上述标记的指针进行减1操作,通常情况下系统会自动完成此功能

4.销毁

   dealloc;从内存中销毁对象。可在类的.m文件中直接重写此方法,当对象真正从内存中销毁时会自动调用:

1 - (void)dealloc
2 {
3     NSLog("%@ is dealloc", self);
4     [super dealloc];
5 }

可以将销毁方法和初始化方法对比一下:

初始化:                销毁:

[super init]           释放实例变量

初始化实例变量       [super dealloc]

不难发现销毁方法与初始化方法的顺序相反。因此只要重写了dealloc方法,[super dealloc]永远都在最后一行。分为两步:1.先将自身的实例变量释放掉2.执行父类中的dealloc方法,释放继承过来的实例变量。

协议

类似于Java C++里的接口对象

copy,需要类使用NSCopying协议

1.伪拷贝

   特点:相当于没有拷贝,只是让外界的对象执行了一次retain操作。 

1 - (id)copyWithZone:(nullable NSZone *)zone
2 {
3     return [self retain];
4 }    

2.浅拷贝

   特点:拷贝的是地址,会初始化一个新的对象,但是新对象和旧对象共用一份内容,改变其中一个对象实例变量的值,另一个也会访问到改变之后的值。

   注意!如果实例变量是字符串且初始化时指向了常量区,那么在拷贝后更改字符串的值,相当于在常量区又重新开辟了一个新的空间,所以这种情况下并不会影响另一个对象实例变量的值。

1 - (id)copyWithZone:(NSZone *)zone
2 {
3      //实例化一个新的对象
4      Hero *hero = [[Hero allocWithZone:zone] init];
5      //为新对象的实例变量赋值  
6      Hero.name = self.name;
7      Hero.level = self.level; 
8      return hero;   
9 }

3.深拷贝

   特点:会重新初始化一个对象,并且内存也是两份,改变其中一个的值,另一个不会发生改变。可以理解为复制粘贴操作。

1 - (id)copyWithZone:(NSZone *)zone
2 {
3      Hero *hero = [[Hero allocWithZone:zone] init];
4      hero.name = self.name;
5      hero.level = self.level;
6      return person;
7 }

【Objective-C学习记录】第二十八天

标签:

原文地址:http://www.cnblogs.com/shvier/p/5086926.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!