说明:
1、计数器
2、@property的内存管理
3、循环语句
4、ARC
(一)内存管理
1、引用计数器的作用:
1> 当使用alloc、new或copy创建一个新对象时,新对象的引用计数器就认为是1,因此就必须调用[p release]/autorelease来使计数器-1;
2> 当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收,若不为0,则在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已退出;
2、引用计数器的操作:
1> [p retain]:计数器+1(retain方法返回对象本身);【给对象发送一条retain消息可使引用计数器值+1】;
2> [p release]:计数器-1(release方法无返回值);【给对象发送一条release消息可使引用计数器值-1】;
3> [p retainCount]:获取当前计数器(%ld获取);【可给对象发送一条retainCount消息获得当前的引用计数器值】;
4> [super dealloc]:当一个对象要被回收时,一定放最后面调用;
3、对象的销毁:
1> 当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存会被系统回收;
2> 当一个对象被销毁时,系统会自动向对象发送一条dealloc对象;
3>
4、引用计数器
1> retain、release的基本使用:
① retain方法返回的是对象本身,计数器+1;([p retain];)
② release可使计数器-1;([p release]);
2> 野指针和空指针:
① 僵尸对象:所占用内测已被回收的对象,僵尸对象不能再使用(不能再调用[p retain],会报野指针错误);
② 野指针:指向僵尸对象(不可用内存的计数器为0的对象)的指针;
③ 空指针(OC中无空指针错误;):没指向任何东西的指针(存储的东西是nil、nul、,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方法代码规范:
3> dealloc方法的代码规范(不要直接调用):
① 当一个对象被回收时,一定要[super dealloc],且放到最后面;
② 对self(当前)所拥有的其它对象做一次release;
7、@property的内存管理:
1> 对象类型:都使用@property (retain) Book * book;//retain:生成的set方法里,release旧值,retain新值===》上面6的set方法;
2> @property参数分类:
① 内测管理相关参数:
。retain:release旧值,retain新值(适用于OC对象);
。assign:直接赋值(默认,适用于非OC对象类型);
。copy:release旧值,copy新值;
② 是否要生成set方法:
。readwrite:同时生成setter和getter的声明和实现(默认);
。readonly:只会生成getter的声明和实现;
③ 多线程管理:
。nonatomic:性能高(一般用这个);
。atomic:性能低(默认,耗性能);
① setter和getter方法的名称(一般不修改,修改后2者都可调用,BOOL类型可修改isCar):
。setter=方法名:;//决定set方法的名称,一定要有个冒号;
。getter=方法名;//决定了get方法的名称(一般用在BOOL类型);
② 总结:
。OC对象类型:@property (nonatomic , retain) 类名 * 属性名;
。非OC对象类型:(基本数据类型:@property (nonatomic,assign) 类型名称 属性名);
。被retain过的属性,必须在dealloc方法中release属性:
1> 表示时间(从1970年1.1日00:00:00开始至此度过的秒):
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> 两端循环引用解决方案(例:Person与Card):
① 一端用retain;
② 一端用assign;
10、autorelease延迟释放使用(占用内存较小时使用,因为不确定池子销毁时间,从而不能及时销毁):
1> autorelease方法的基本语法:
① [p autorelease]方法会返回对象本身;
② [p autorelease]会将对象放到一个自动释放池中;
③ 当自动释放池被销毁时,会对池子里的所有对象做一次[p release]操作;
④ 调用完autorelease方法后,对象的计数器不变;
2> Autorelease使用的好处:
① 不用再关心对象释放的时间;
② 不用再关心什么时候调用release;
3> Autorelease的使用注意:
① 占用内存较大的对象不要随便使用autorelease;
② 占用内存较小的对象使用autorelease,没有太大影响;
4> 自动释放池:
① 创建自动释放池(Main函数中使用):
② 在iOS程序运行过程中,会创建无数个池子,这些池子都是以栈结构存在(先进后出);
③ 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池;
④
5> 错误写法:
① alloc 之后调用了autorelease后,又调用release(如:Person *p=[[[Person alloc] init ] autorelease]; [p release];);
② 连续调用多次autorelease(如:Person *p=[[[[Person alloc] init ] autorelease] autorelease];);
6> autorelease使用规律:
① 系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelese的(如:[NSString stringWithFromat:…]或[NSDaate date]…..);
② 开发中经常会提供一些类方法(以类名开头With成员变量:personWithAge),快速创建一个已经autorelease过的对象;
。创建对象时不要直接用类名,一般用self;
11、ARC的使用(编译器特性):编译器编译代码时若发现alloc则自动生成release;
1> ARC判断准则:只要没有强指针指向对象,就会释放对象;
2> 指针分2种:
① 强指针(__strong,可省略):默认情况下,所有的对象都为强指针;
② 弱指针(__weak):
3> 以前的retain改为strong,其它什么都不变;
4> ARC特点:
① 不允许调用release、retain、retainbCount;
② 允许重写dealloc、但不允许调用[super delloc];
③ @property的参数:
strong:成员变量为强指针,相当于原来的retain(适用于OC对象类型);
weak:成员变量为弱指针,相当于原来的assign(适用于OC对象类型);
assign:适用于非OC对象类型;
5> Xcode的ARC转换功能:
① 自己项目: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;