黑马程序员——内存管理

来源:互联网 发布:控制微信摇骰子软件 编辑:程序博客网 时间:2024/05/17 13:08

---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

一、内存管理的概念:

我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在OC中对象是存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上)。如果一个对象创建并使用后没有得到及时释放那么就会占用大量内存。其他高级语言如C#、Java都是通过垃圾回收来(GC)解决这个问题的,但在OC中并没有类似的垃圾回收机制,因此它的内存管理就需要由开发人员手动维护。

二、内存管理的重要意义:

OC中的内存管理机制跟C语言中指针的内容是同样重要的,要开发一个程序并不难,但是优秀的程序则更测重于内存管理,它们往往占用内存更少,运行更加流畅。虽然在新版Xcode引入了ARC,但是很多时候它并不能完全解决你的问题。在Xcode中关闭ARC:项目属性—Build Settings--搜索“garbage”找到Objective-C Automatic Reference Counting设置为No即可。

三、引用计时器

每个OC对象都有自己的引用计时器,占4个字节,这个计时器是一个整数,表示对象被引用的次数,也就是有多少人在使用这个OC对象
当计时器值为0的时,对象占用的内存就会被系统回收
计时器操作:

1.给对象发送一条retain消息,计时器值+1

2.给对象发送一条release消息,计时器-1

3.给对象发送retainCount消息,可以获得计时器当前值

对象销毁:
当计时器数值为1,被系统销毁时,会给对象发送一个dealloc消息,一般会重写dealloc方法,重写时,必须调用[super dealloc],不能直接调用
调用alloc,就对应的调用release;调用retain,对应调用release

四、野指针、空指针、僵尸对象概念

  • 僵尸对象:内存已经被回收的对象,僵尸对象是不能再使用的,而且一旦成为僵尸对象的对象,不可能在复活
  • 野指针:指向僵尸对象(即内存不可用的对象)的指针,给野指针发送消息,会报一个Bad-Acc错误,即坏消息访问错误
  • 空指针:没有指向任何对象的指针(比如对象储存的时nil,null,0),给空指针发送消息不会出错

五、setter内存管理

1.谁创建,谁release,如果用new或者alloc创建一个对象,那么就必须调用release
2.谁retain,谁release,无论这个对象是如何生成的,都要调用release
总结:
1.当要使用或者占用某对象的时候,就该让对象的计数器+1,即让对象做一次retain操作
2.不想使用或占用某个对象的时候,就该让对象的计数器-1,即让对象做一次release操作
注:基本数据类型不需要管理内存,仅对对象管理

六、setter、alloc内存管理代码规范

1.只要调用了alloc,必须有release(autourelease),如果对象不是通过alloc创建的,就不需要release
2.set方法的代码规范

1>基本数据类型,直接赋值,无需管理

- (void)setAge:(int)age     //基本数据类型不需要管理内存{    _age = age;}
2>OC对象类型
- (void)setCar:(Car *)car{   // 先判断是不是新传进来的对象     if (car != _car) {                 [_car release];          // 在创建新车的同时,也对旧车做一次release操作        _car = [car retain];    // 对新车做一次retain操作  }}
3.dealloc方法的代码规范
1>一定要[super dealloc],而且一定要放到最后
2>对当前对象(self)所拥有的其他对象做一次release
- (void)dealloc{    [_car release];    NSLog(@"%d岁的Person对象被回收!!!",_age);    [super dealloc];}

七、@property内存管理

可以在@property后面的括号里加上参数
比如:
在.h声明文件中写上如下一行代码

@property (retain) Book *book;
这就相当于在.m文件中执行了如下的代码功能
- (void)setBook:(Book *)book{    if (_book != book) {        [_book release];        _book = [book retain];    }}
@property后面可以加的情况
1.set方法内存管理相关的参数
  • retain:release旧值,retain新值(用于OC对象类型)
  • assign:直接赋值(默认,适用于非OC对象)
  • copy:release旧值,copy新值

2.是否要生产set方法

  • readonly : 只会生产getter的声明和实现
  • readwrite:同时生成setter和getter的声明以及实现
3.多线程管理
  • nonatomic:性能高(一般用这个)
  • atomic:性能低(默认)
4.setter方法和getter方法的名称
  • setter:决定了setter方法的名称,但方法后面记得要有个冒号
  • getter:决定了get方法的名称而已
  • 但是getter方法一般用在BOOL类型中,setter不常用
@property (getter = isRich) BOOL rich;  int main(){    Person *p = [[Person alloc] init];    p.rich = YES;   // set这个人有钱    BOOL b = p.isRich;  //get这个人是否有钱return 0;}

八、@property参数试使用

注:@property后面的参数可以混合使用,但类型不能冲突


@property的参数分为三类,也就是说参数最多可以有三个,中间用逗号分隔,每类参数可以从上表三类参数中人选一个。如果不进行设置或者只设置其中一类参数,程序会使用三类中的各个默认参数,默认参数:(atomic,readwrite,assign)
一般情况下如果在多线程开发中一个属性可能会被两个及两个以上的线程同时访问,此时可以考虑atomic属性,否则建议使用nonatomic,不加锁,效率较高;readwirte方法会生成getter、setter两个方法,如果使用readonly则只生成getter方法;关于set方法处理需要特别说明,假设我们定义一个属性a,这里列出三种方式的生成代码:
assign,用于基本数据类型

-(void)setA:(int)a{    _a=a;}
retain,通常用于非字符串对象
-(void)setA:(Car *)a{    if(_a!=a){        [_a release];        _a=[a retain];    }}
copy,通常用于字符串对象
-(void)setA:(NSString *)a{    if(_a!=a){        [_a release];        _a=[a copy];    }}
0 0