------- <a href="http://www.itheima.com" target="blank">Windows Phone 7手机开发</a>、<a href="http://www.itheima.com" target="blank">.Ios培训</a>、期待与您交流! -------
内管管理是oc学习中,十分重要的一章节,是重点,也是难点。但自从苹果启用了ARC机制后,使用xcode编写oc程序,基本上不需要开发者们关注内存是否被收回,因为系统自动会帮助你回收,就像老师上课视频里说的,开起ARC后,代码你怎么写都是对的。那么对于我们初学者来说,要初步的掌握ARC机制,就需要把苹果的ARC机制关闭再进行学习。需要注意一点的是,oc中的ARC机制,并不等同于Java中的垃圾回收,Java中的垃圾回收,是运行时的特性。而oc中的ARC机制,不是运行时特性,它是编译器特性,编译器特性是指当编译器发现代码中有alloc、retain、copy后,系统会在相应位置自动加上release操作。
首先,我们的得知道如何关闭ARC机制,新版的xcode与老版本的关闭,操作上有所不同。不仅仅如此,打开ARC后我们还需要打开僵尸对象检测功能,僵尸对象是指,当对象的内部引用计数器已经被清零了,那么这个对象的内存空间会被回收,那么这个对象就叫做僵死对象,如果一个对象已经成为僵死对象了,开发者再用指针去指向或者操作这个对象,编译器就会报野指针错误,指出该指针指向了一块坏的或者是不可用的内存区域。
关闭ARC以及打开僵死对象检测的步骤:
通过这三个步骤,我们为接下来内存管理的基础学习建立了基本的环境。
多对象内存管理的代码演示:
main函数:
#import <Foundation/Foundation.h>
#import "Boss.h"
#import "Macbook.h"
#import "Plane.h"
int main()
{
Boss *b = [[Boss alloc] init]; // 有alloc,后面必有release,alloc操作使对b对象计数器加1,b = 1
b.age = 45;
Macbook *m = [[Macbook alloc] init]; // 有alloc,后面必有release,alloc操作使m对象计数器加1,m = 1
b.macbook = m; // setter方法中,使m的计数器加1,m = 2
Plane *p = [[Plane alloc] init]; // 有alloc,后面必有release,alloc操作使p对象计数器加1,p = 1
b.plane = p; // setter方法中,使p的计数器加1,p = 2
[p release]; // 调用release方法,使p的计数器减1,p = 1
NSLog(@"%ld",[p retainCount]); // retainCounter方法,返回的是NSUInteger类型,也就是长整型
[m release]; // 调用release方法,使m的计数器减1,m = 1
NSLog(@"%ld",[m retainCount]); // retainCounter方法,返回的是NSUInteger类型,也就是长整型
[b release]; // b = 0,b对象被回收,调用Boss类中的dealloc方法,使得p与m计数器也清零,对象也被回收
return 0;
}
Boss类的声明与实现:
#import <Foundation/Foundation.h>
#import "Macbook.h"
#import "Plane.h"
@interface Boss : NSObject
{
int _age; // Boss的年龄,属于基本数据类型,不需要内存管理代码
Macbook *_macbook; // Boss拥有的macbook对象,属于oc对象,需要内存管理代码
Plane *_plane; // Boss拥有的Plane对象,属于oc对象,需要内存管理代码
}
// setter与getter方法的声明
- (void)setAge:(int)age;
- (int)age;
- (void)setMacbook:(Macbook *)macbook;
- (Macbook *)macbook;
- (void)setPlane:(Plane *)plane;
- (Plane *)plane;
@end
#import "Boss.h"
@implementation Boss
- (void)setAge:(int)age
{
_age = age;
}
- (int)age
{
return _age;
}
- (void)setMacbook:(Macbook *)macbook
{
if (_macbook != macbook) // 检测新传入的对象是否与之前的对象相同,这样可以避免重复赋值后,出现野指针错误
{
[_macbook release];
_macbook = [macbook retain]; // retain方法,是对象方法,调用后返回对象本身,并且使该对象计数器加1
}
}
- (Macbook *)macbook
{
return _macbook;
}
- (void)setPlane:(Plane *)plane
{
if (_plane != plane) // 检测新传入的对象是否与之前的对象相同,这样可以避免重复赋值后,出现野指针错误
{
[_plane release];
_plane = [plane retain]; // retain方法,是对象方法,调用后返回对象本身,并且使该对象计数器加1
}
}
- (Plane *)plane
{
return _plane;
}
- (void)dealloc
{
NSLog(@"年龄为%d的Boss对象被回收",[self age]); // 打印,用于检测对象被回收后,是否调用了dealloc方法
[_macbook release]; // 将该类,即是Boss类拥有的对象全部释放一次,注意是对象,基本上数据类型不是对象
[_plane release];
[super dealloc]; // dealloc方法的最后必须调用父类的dealloc方法,初学者不必深究
}
@end
Macbook类的声明与实现:
#import <Foundation/Foundation.h>
@interface Macbook : NSObject
@end
#import "Macbook.h"
@implementation Macbook
- (void)dealloc
{
NSLog(@"Macbook对象被回收");
[super dealloc];
}
@end
Plane类的声明与实现:
#import <Foundation/Foundation.h>
@interface Plane : NSObject
@end
#import "Plane.h"
@implementation Plane
- (void)dealloc
{
NSLog(@"Plane对象被回收");
[super dealloc];
}
@end
程序执行后的结果为:
结合上面代码以及代码里面的注释,可以比较清楚的认识到多对象内存关的初步知识。总结为几句话:有始有终,有加就有减,曾经让对象计数器加1,就必须在最后让对象计数器减1。最后还得注意一点的是,dealloc方法是对象方法,但是一般情况下不要直接调用,而是对象内部计数器清零后,系统会自动调用dealloc方法,把对象内存回收,被回收掉的对象,不能再进行操作,包括retain以及retainCount操作。