OC复习总结:
这个文件是在学习完C语言的基本用法后,回顾C语言的一些语法和易错,不易理解的一下内容,可能会存在内容不连续的情况.
本文内容,有参考自 M了个J的博客 和 lizze_yun的博客 根据自身的学习进行了部分的摘抄和扩写
原文请参考:http://www.cnblogs.com/mjios/tag/objective-c/default.html?page=1
http://blog.csdn.net/zhangyun2013?viewmode=contents
内存管理:
1、引用计数器
1->每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象
2->每个OC对象内部专门有4个字节的存储空间来存储引用计数器
基本数据类型都是存放在栈里,而对象都是放在堆里,存放在栈里的变量用完之后系统会自动回收它所占用的内存,但是放在堆里的对象就需要手动回收其占用的内存
方法的基本使用
1->retain:计数器+1,会返回对象本身 一般在@property处使用
2->release:计数器-1,没有返回值 一般在 setter方法和 dealloc或者主函数中使用
3->returnCount:获取当前的计数器的值
4->dealloc:
*一定会先释放他所拥有的资源 对应@property如果使用retain此处要进行release
*当一个对象要被收回的时候,就会调用
*一定要调用[super dealloc],这句调用要放在最后面
其他基本概念:
1->僵尸对象:所占用内存已经被回收,僵尸对象不能再使用
2->野指针:指向僵尸对象(不可用内存)的指针
3->空指针:没有指向任何东西的指针(存储的东西是nil、null、0),给空指针发送消息不报错
注:野指针错误:错误EXC_BAD_ACCESS:访问了一块坏的内存(已经被回收、已经不可用的内存)
内存管理原则:
1.只要某个对象还在被使用,那么这个对象就不会被回收
2.你想使用(占用)某个对象,就应该让对象的计数器加1,(让对象做一次retain操作)
3.你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release操作)
4.谁retain,谁release
如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease换句话说,不是你创建的,就不用你去[auto]release
5.谁alloc,谁release。
只要你调用了retain,无论这个对象是如何生成的,你都要调用release
setter方法的标准写法:
- - (void)setCar:(Car *)car
- {
- //1.先判断是不是新传进来的对象
- if (car != _car)
- {
- //2.对旧对象做一次release
- [_car release];
- //3.对新对象做一次retain
- _car = [car retain];
- }
- }
3.dealloc方法的代码规范
1->一定要[super dealloc],而且放到最后面
2->对self(当前)所拥有的其他对象做一次release
- - (void)dealloc
- {
- [_car release]; // 当前对象的成员变量_car
- [super dealloc];
- }
3.两端循环引用解决方案
一端用retain
一端用assign
@property (nonatomic,retain)Card *car
@property (nonatomic,assign)Person *person
@class的好处:
1.解决了循环import的问题(只需要在.h文件中用@class声明,在需要的时候,才在.m文件中import这个类)
2.提高了性能(#import意思是复制,假如有很多类在头文件中都引用了Card这个类,但是一旦Card这个类改变之后,其他那些类都得重新复制一遍,性能较低,用@class的话就不需要)
@class和import的区别:
1.#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息
2.如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来 讲,使用@class方式就不会出现这种问题了
3.在.m实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类
autorelease的基本用法
autorelease的好处
。不用关心对象释放的时间
。不用关心什么时候调用release
autorelease的使用注意
。占用内存较大的对象不要随便使用autorelease
。占用内存较小的对象使用autorelease,没有太大影响
注:autorelease实际上只是把对release的调用延迟了,对于每一次autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用Release(注意并不是直接销毁 只是执行一次release操作而已)
ARC:
Automatic Reference Counting(自动引用计数器)
2.ARC的基本原理(判断准则):只要没有强指针指向对象,就会释放对象
指针分两种:强指针,默认情况下,所有的指针都是强指针__strong
弱指针,__weak
3. ARC特点:
(1)不允许调用release、retain、retainCount。
(2)允许重写dealloc,但是不允许调用[super dealloc];
(3)@property的参数
strong:成员变量是强指针,相当于以前retain(使用OC对象)
weak:成员变量是弱指针,相当于以前assign(使用OC对象)
assign:基本数据类型,直接赋值。(适用于非OC对象)
(4)以前的retain,改为用strong,其余不变
如: 以前(手动管理内存时)@property (nonatomic,retain) Car *car;
现ARC机制中改为:@property (nonatomic,strong) Car *car;
ARC的循环引用
- int main()
- {
- Dog *d = [[Dog alloc] init];
- Person *p = [[Person alloc] init];
- p.dog = d;
- d.person = p;
- }
两个都是强指针,所以没办法被释放,解决方法: 一端用strong,一端用weak
Dog 端 : @property (nonatomic,strong) Person *person;
Person端:@property (nonatomic,weak) Dog *dog
ARC的转换功能:
如果想把非ARC转换为ARC的,那么在xcode菜单栏中的edit下的refactor中找到covert to Objective-C ARC ,选择项目进行转换即可。
如果想要某些文件是非ARC的,那么在xcode6.0.1中如下图找到编译文件,双击这个文件就会出现一个对话框,在里边写上-fno-objc-arc,即可
Block
用来保存一段代码,有时也称为代码段或代码块,它是封装了一段代码,可以在任何时候执行
定义block变量:
int (^sumBlock)(int,int);
定义了一个叫sumBlock的block对象,它带有两个int参数,返回int
实现block的声明
sumBlock(int,int) = ^(int a, int b){
return a + b;
};
也可以把block变量定义和具体实现写在一起
int (^MySum)(int, int) = ^(int a, int b) {
return a+b;
};
Block可以访问局部变量,但是不能修改。
如果要修改就要加关键字:__block
也可先用typedef先声明类型,再定义变量进行赋值
typedef int (^MySum)(int,int);
MySum sum = ^(int a,int b) {
return a + b;
};
协议:Protocol
类遵守协议:
@interface类名 : 父类 <协议名称>
@end
协议中声明了一些方法,如果某个类遵守了这份协议,就相当于这个类可以继承到这些方法的声明,然后也必须对某些方法进行实现
@required:方法前只要加上这个关键字,表示这个方法必须要实现(若不实现,编译器会发出警告)
@optional:这个方法不一定要实现
协议遵守协议
@protocol协议名称 <协议1,协议2>
@end
定义变量时指定协议(限制变量或属性遵守某个协议)
NSObject<myProtocol> *objc3 = [[Person alloc] init] ;
//只有Person类遵守myProtocol协议时 才不会报错
@property中声明的属性也可以用做一个遵守协议的限制
@property (nonatomic,strong) id<myProtocol>obj;
意味着生成set方法设置这个对象时,此对象必须要遵守myProtocol这个协议
协议的声明:
@Protocol myProtocol(协议名称);.h文件中
#import “myProtocol.h”.m文件中