黑马程序员—(iOS开发)OC内存管理机制---(十)

  ------- android培训iOS培训Java培训.NET培训期待与您交流! ----------

说明:

1、计数器

2、@property的内存管理

3、循环语句

4、ARC


(一)内存管理

1、引用计数器的作用:

1> 当使用allocnewcopy创建一个新对象时,新对象的引用计数器就认为是1,因此就必须调用[p release]/autorelease来使计数器-1

2> 当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,若不为0,则在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已退出;

2、引用计数器的操作:

1> [p retain]:计数器+1retain方法返回对象本身);【给对象发送一条retain消息可使引用计数器值+1】;

2> [p release]:计数器-1release方法无返回值);【给对象发送一条release消息可使引用计数器值-1】;

3> [p retainCount]:获取当前计数器(%ld获取);【可给对象发送一条retainCount消息获得当前的引用计数器值】;

4> [super dealloc]:当一个对象要被回收时,一定放最后面调用;

@implementation中:

-voiddealloc

{

[_book release];//@implementation中实现的对象

NSLog(@对象被回收时调用);

[super dealloc];

}

3、对象的销毁:

1> 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存会被系统回收;

2> 当一个对象被销毁时,系统会自动向对象发送一条dealloc对象;

3> 

4、引用计数器

1> retainrelease的基本使用:

① retain方法返回的是对象本身,计数器+1;([p retain];

② release可使计数器-1;([p release]);

2> 野指针和空指针:

① 僵尸对象:所占用内测已被回收的对象,僵尸对象不能再使用(不能再调用[p retain],会报野指针错误);

② 野指针:指向僵尸对象(不可用内存的计数器为0的对象)的指针;

③ 空指针(OC中无空指针错误;):没指向任何东西的指针(存储的东西是nilnul,0),给空指针发送消息不会报错;

④ EXC_BAD_ACCESS:访问了一块坏的内存(已被回收、不可用的内存),野指针错误

3> 多对象内存管理

① 你想使用(占用)某个对象,就应让对象的计数器+1[p retain]);

② 你不想使用(占用)某个对象,就应让对象的计数器-1[p release]);

③ 谁[p retain],谁[p release]

④ 谁[[p alloc] init],谁[p release]

4> 

5、访问成员变量:

1> 直接访问成员变量:_speed;

2> 直接访问成员变量:self->_speed;

3> get方法:self.speed;

3> get方法:[self speed];

6、内存管理代码规范:

1> 只要调用[[p alloc] init],就必须[p release]/autorelease;

2> set方法代码规范:

① 基本数据类型:直接复制

-(void) setAge:(int)age

{

_age = age;

}

② 成员变量的set方法中(对象变量):

-voidsetCar:(Car *)car

{

If(car != _car)

{

//对当前正在使用的车(旧车)release

[_car release];

//对新车做retain

_car = [car retain];

}

}

3> dealloc方法的代码规范(不要直接调用):

① 当一个对象被回收时,一定要[super dealloc],且放到最后面;

② 对self(当前)所拥有的其它对象做一次release;

@implementation中:

-voiddealloc

{

[_car release];//@implementation中实现的对象

NSLog(@对象被回收时调用);

[super dealloc];

}

7、@property的内存管理:

1> 对象类型:都使用@property (retain) Book * book;//retain:生成的set方法里,release旧值,retain新值===》上面6set方法;

2> @property参数分类:

① 内测管理相关参数:

retainrelease旧值,retain新值(适用于OC对象);

assign:直接赋值(默认,适用于非OC对象类型);

copyrelease旧值,copy新值;

② 是否要生成set方法:

readwrite:同时生成settergetter的声明和实现(默认);

readonly:只会生成getter的声明和实现;

③ 多线程管理:

nonatomic:性能高(一般用这个);

atomic:性能低(默认,耗性能);

①  settergetter方法的名称(一般不修改,修改后2者都可调用,BOOL类型可修改isCar):

setter=方法名:;//决定set方法的名称,一定要有个冒号;

getter=方法名;//决定了get方法的名称(一般用在BOOL类型);

 

② 总结:

OC对象类型:@property (nonatomic , retain) 类名 属性名;

@property (nonatomic ,retain) Car *car;

@property (nonatomic , retain) id Car;

@property (nonatomic,strong) Car *car;//使用ARC之后,没有retain类型;

。非OC对象类型:(基本数据类型:@property (nonatomic,assign) 类型名称 属性名);

       @property (nonatomic,assign) int age;

。被retain过的属性,必须在dealloc方法中release属性:

如:-voiddealloc

{

[_car release];

[super dealloc];

}

1> 表示时间(从19701.1000000开始至此度过的秒):

@property (retainassign) time_t  time;或者@property (retainassign) long time;

8、模型设计

   1> 单例模式:

       ① 设计原理:始终返回一个实例,即一个类始终只有一个实例;

   2> 创建单例设计模式基本步骤:

           ① 声明一个单例对象的静态实例,并初始化为nil;

   ② 创建一个类的类方法,生成一个该类的实例,当且仅有这个类实例nil时,进行实例化;

   ③ 覆盖allocWithZone:方法,确保用户直接分配和初始化后,不会产生新的对象; 

   ④ 实现NSCopying协议,覆盖release、autorelease、retain,retainCount方法,以确保单例的状态;

   ⑤ 在多线程环境中,注意使用@synchronized关键字,确定静态实例被正确和初始化;

9、循环retain@class

1> @interface中,在@interface之前定义:@class Card//@class表示仅仅告诉编译器card是一个类;

2> 开发中引用一个类的规范:

① .h文件中用@class来声明类

② .m文件中用#import来包含类的所有东西

3> @class#import的区别:

① #import方式会包含被引用类的所有信息,包括被引用类的变量及方法;@class方式只告诉编译器在A.h文件中B *b只是类的声明,具体类里的消息不需知道,等文件真正用到时才去查看B类中的信息;

② 若多个文件中都#import了同一个文件或这些文件依次被#import,那么头文件稍有改动,后面引用到此文件的所有类将需重新编译一次,这样相对来看,效率比@class降低了;

③ .m实现文件中,若需引用到被引用类的实体变量或方法时,还需使用#import方式引入被引用类;

4> 两端循环引用解决方案(例:PersonCard):

① 一端用retain

② 一端用assign

10、autorelease延迟释放使用(占用内存较小时使用,因为不确定池子销毁时间,从而不能及时销毁):

1> autorelease方法的基本语法:

① [p autorelease]方法会返回对象本身;

② [p autorelease]会将对象放到一个自动释放池中;

③ 当自动释放池被销毁时,会对池子里的所有对象做一次[p release]操作;

④ 调用完autorelease方法后,对象的计数器不变;

2> Autorelease使用的好处:

① 不用再关心对象释放的时间;

② 不用再关心什么时候调用release;

3> Autorelease的使用注意:

① 占用内存较大的对象不要随便使用autorelease

② 占用内存较小的对象使用autorelease,没有太大影响;

4> 自动释放池:

① 创建自动释放池(Main函数中使用):

iOS5.0之前的方式

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

Person *pp = [[[Person alloc] init]autorelease];

[pool release];//或者[pool drain];

iOS5.0之后的方式:

@autoreleasepool

{  //{开始代表创建了释放池(ios5.0后)

Person *p=[[[Person alloc] init ] autorelease];//

}

② iOS程序运行过程中,会创建无数个池子,这些池子都是以栈结构存在(先进后出);

③ 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池;

④ 

5> 错误写法:

① alloc 之后调用了autorelease后,又调用release(如:Person *p=[[[Person alloc] init ] autorelease]; [p release];;

② 连续调用多次autorelease(如:Person *p=[[[[Person alloc] init ] autorelease] autorelease];);

6> autorelease使用规律:

① 系统自带的方法里面没有包含allocnewcopy,说明返回的对象都是autorelese的(如:[NSString stringWithFromat:][NSDaate date]..);

② 开发中经常会提供一些类方法(以类名开头With成员变量:personWithAge),快速创建一个已经autorelease过的对象;

。创建对象时不要直接用类名,一般用self

如:+idPerson

{

return [[[self alloc] init] autorelease];

}

11、ARC的使用(编译器特性):编译器编译代码时若发现alloc则自动生成release

1> ARC判断准则:只要没有强指针指向对象,就会释放对象;

2> 指针分2种:

① 强指针(__strong,可省略):默认情况下,所有的对象都为强指针;

② 弱指针(__weak):

3> 以前的retain改为strong,其它什么都不变;

4> ARC特点:

① 不允许调用releaseretainretainbCount

② 允许重写dealloc、但不允许调用[super delloc]

③ @property的参数:

strong:成员变量为强指针,相当于原来的retain(适用于OC对象类型);

weak:成员变量为弱指针,相当于原来的assign(适用于OC对象类型);

assign:适用于非OC对象类型;

5> XcodeARC转换功能:

① 自己项目:Edit--Refactor--Convert to OC ARC;

② 引入第三方不是arc的框架:项目右击--Build Phases--选中.m文件--编写:【-fno-objc-arc;

③  将项目转为arc的框架:项目右击--Build Phases--选中.m文件--编写:【-f-objc-arc;

④ 查看自己项目是否为arc项目:项目右击--Build Settings--搜索auto--Apple LLVM中是否为Yes;

6> ARC循环引用:

① (ARC类型)一端用strong,一端用weak

② (非ARC类型)一端用retain,一端用assign



  ------- android培训iOS培训Java培训.NET培训期待与您交流! ----------



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值