您的位置:首页 > 其它

oc基础知识

2014-08-16 21:59 225 查看
重点知识(内存管理)

管理范围:任何继承了NSObject的对象。

预备知识内存分配 :栈区,堆区,全局区,文字常量区

一个由C编译的程序占用的内存分为以下几个部分

1、栈区(stack) 由编译器自动分配释放,存放函数的参数值,局部变量的值等

。其操作方式类似于数据结构中的栈。

2、堆区(heap) 一般由程序员分配释放若程序员不释放,程序结束时可能由系统

回收。

注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3、全局区(静态区)(static),全局变量和静态变量的存储是放在一块的,初

始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量

在相邻的另一块区域。程序结束后由系统释放。

4、文字常量区 常量字符串就是放在这里的。程序结束后由系统释放

5、程序代码区 存放函数体的二进制代码。

栈:放一些局部变量。指针式局部变量放在栈里。栈里面的东西自动回收。

堆:放动态产生的变量。 对象的内存放在堆里面。堆里面的东西不能自动回收。

堆里面的东西是程序员手动释放的。

oc里尽管没有任何指针指向对象了,但是只要他在堆空间里,就不会回收。

怎样回收:

只有给对象发送一条消息,他就回收了。

什么是发送消息:

就是调用方法,调用对象的某个方法,才能销毁。

怎么判断需不需要回收:

每个oc对象都有自己的引用计数器,是一个整数,占用4个字节的存储空间。表示对

象引用的次数,当引用引用计数器为0时,把对象回收。

引用计数器的作用:

1,当使用alloc,new,copy创建对象时,新对象的引用计数器默认值是1.

2,当一个对象的引用计数器值为0时,对象占用的内存就会被系统收回。

3,如果对象的引用计数器值不为0,那么在整个程序运行过程,他占用的内存就不可

能被收回,除非整个程序已经退出。

引用计数器的操作:

1,给对象发送一条retain消息,可以使计数器值+1.

2,给对象发送一条release消息,可以使引用计数器值-1.

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

对象被回收的两种情况:

1,程序员通过代码在运行过程中就把对象干掉。

2,当程序员退出时,整个程序占用存储空间会自动回收。

怎么验证对象有没有人用:

1,重写对象的dealloc方法,在dealloc括号里打印,有打印说明dealloc有调用,

对象被回收。

调用的dealloc方法,一定要调用super的方法[super dealloc];一定要放到最后面

。当一个对象被回收是,系统会自动调用[super dealloc]方法。计数器值为0时,

系统会自动调用[super dealloc]方法。

对象的销毁:

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

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

3,一个般会重写dealloc的方法,在这里释放相关资源,dealloc就像对象的遗言。

4,一旦重写了dealloc方法,就必须用[super dealloc],并放在最后调用。

5,不要直接调用dealloc方法。

6,一旦对象被回收了,他占用的内存就不可用,坚持使用会导致崩溃.(野指针错误



野指针:指向了僵尸对象(不可用内存)的指针。

僵尸对象:所占用内存已经被回收的对象。

空指针:没有指向任何对象的指针。

oc里面给空指针发送消息,不报错。

给野指针发送消息,报错。在程序运行过程中报错,直接闪退。

什么是野指针错误:

指向了僵尸对象,或者不空用内存的指针。

EXC BAD ACCEESS -> message sent to dealloc cated instance.访问了一块不

能访问的内存空间。(野指针错误)。

Xcod 打开监测僵尸对象程序: Edit streme ->Diagnastics ->oc ->Enable

Zombieobject.

retain是有返回值的,返回值是(id),任何的oc对象。

注意:retain方法返回的是对象本身(他自己)。谁调用retain就返回谁。

set方法的内存管理:利用@property参数

1,@property(retain)Book*book

return : 生成set方法,release旧值,retain新值

2.@ property(readwrite) 可读可写。

@property(readonly)只读

修改getter和setter方法的名称:

@property(getter = abc)int weight; 修改getter成员变量的名称。

@property(getter = abc ,setter = setAbc:)int weight; set方法后一定要有

冒号。

setter方法:决定了方法名后一定要有冒号。

getter方法:决定了方法的名称。

getter方法一般用在BOOL类型。

提高性能(多线程管理):

1,nonatomic 性能高

2,atomic 性能低(默认)

内存管理的相关参数:

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

2,copy:release旧值,copy新值。

内存的管理代码规范:

只要调用alloc,就必须有release或autorelease。如果对象不是alloc产生的,

就不用release。

set方法的代码规范:

1,基本数据类型:直接赋值

2,OC对象类型:

先判断是否是新对象,使用新对象,对新对象加一次retain,对旧对象减一次

release.

- (void)setCar:Car*car

{

if (_car != car)

{

[_car release]

_car = [car retain];

}

}

dealloc方法代码规范:

1,一定要调用[super dealloc],一定要放到最后面。

2,当前对象(self),所拥有对象做一次release.

多对象内存管理

当你想使用某个对象的时候,你应该对他的计数器加1,不想用了减1。(有加有

减)谁retain,谁release。谁alloc,谁release。

补充:访问成员变量的方法有:

直接调用

1,_成员变量;

2,self->成员变量;

间接调用:通过get方法

3,self.成员变量;

4,[self 成员变量]

循环引用:

URL:代表资源路径

@class 声明一个类,仅仅告诉编译器某个名称是一个类。在.h文件中用@class来声

明。

在开发中引用一个类的规范

1,在.h文件中用@class来声明类

2,在.m文件中用#import来包含类的所有东西。

例如:Car这个类被其他100个类引用着,引用这个类直接用#import

坏处;当我修改了Car其中的一点东西,其他的类就要重新拷贝,大大降低我们的编

译效率。

@class的好处:

1,解决循环引用的问题

2,提高了性能

所以为了提高编译效率,一般在头文件不用#import 特殊的是父类,因为继

承:NSObject

面试题:@class 和 @import 的区别

1,#import方式包括被引用类的所有信息,包括被引用类的变量和方法。

@class方式知识告诉编译器在.h文件中,B*b知识累的声明,具体这个类是什么意思

,这里不需要知道,等实现文件中真正要用到时,才会真正查看B类中信息。

2,如果有上百个头文件都#import了同一个文件,或者一次被#import;那么一旦最

开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍。这样的

效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了。

3,在.m 实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用

#import方式引入被引用类。

面试题:循环引用问题怎么解决

当真出现两端循环引用 解决办法是:一端用retain ,另一端用 assign.

autorelease 半自动释放

其实autorelease并不是自动释放,他只是延迟了对象被释放的时间,等释放池被销

毁,才能做release.

基本用法:

1,autorelease 会将对象放到一个自动释放池中

2,当自动释放池(autoreleasepool{ })被释放时,会对池子里的所有对象做一个

release操作。(仅仅是一次release,池子被销毁,对象不一定会销毁)

3,autorelease会返回对象本身

4,调用完autorelease方法后,对象计数器不变 ,怎么理解这句,就是autorelease不会是对象-1,

只会把对象放到池里,是池释放时对里面所有的对象做一次-1.所以说记数器不变。

自动释放池

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

出)。

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

创建释放池有两种方式:

1,@autorelease{

这是ios5.0后的方式

}

2,5.0之前这样创建

NSAutoreleasepool=[[NSAutoReleasePool alloc] init];

[pool release];

以前销毁释放池还有一个方法叫 drain (榨干的意思)

[pool drain]一般用在mac上,ios用release.

自动释放池其实是以栈的形式存在的,栈是以数据结构存放自动释放池的。

栈的特点:先进后出。创建第一个释放池会放在栈的最底部。

autorease好处:

不用关心对象释放的时刻,不用关心什么时候调用release.

autorease 缺点:

不能精确控制对象的释放时间,在开发中药做一个精确控制。

autorelease:一般只适用于占用内存比较小的对象。

什么叫占用内存比较小的对象:

就是说你对象里面的数据类型,基本上都是int float double 这些东西。如果

你的对象里面包含了很多复杂的东西,比如说@property Car 车啊,一大堆东西,

person对象就很占用内存,因此一个person对象占用了很多对象。像这种比较大型

的对象,不要随便使用autorelease。

面试题:

@autorelease pool{

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

池子一销毁对你的池子做了两次release.

野指针错误。

}

autorelease

1,系统自带中,如果不含alloc,new,copy,那么这些方法返回的对象都是已经

autorelease 过的了。

[NSString stringWithFomart....]

[NSDate date] 这些不需要

创建字符串对象的方式:

1,NSString *str = @"123456"

2,NSString *str = [NSString stringWithFormat:@“age is %d”,10];

换串 NSNumber *number = [[NSNumber alloc]initWithInt:10];

2,开发中经常写一些类方法快速创建一个autorelease的对象,创建对象的时候不

要使用类名,要用self.

比如:

+ (id)Person

{

return [[self alloc] init autorelease];

}

+ (id)PersonWithAge:(int)age;

{

Person *p = [self Peron];

p.age = 10;

return p;

}

- (id)dealloc

{

[super dealloc]

}

ARC机制(自动生成释放内存的代码)

oc中arc是编译器特性。

什么是编译器特性:

在编译代码的时候,编译器会自动检测,那里需要插入释放内存的代码。

ARC的判断准则:

只要没有强指针指向对象,就会释放对象。

强指针:默认情况下所有的指针都是强指针 __strong. 两个下划线组成

弱指针:决定不了对象要不要释放 __weak.

ARC好处:

只要弱指针指向对象不存在,它会自动把弱指针清空。(不清空会有野指针错误

)。

弱指针使用场合:

循环引用,在ARC情况下,当两端循环引用的时候,一端用weak,另一端用strong。

在非ARC情况下,循环引用,一端用retain,另一端用assign。

ARC特点:

1,不允许调用 release ,retain

2,允许重写dealloc,但不允许调用[super dealloc]

3,@property的参数中retain改写成strong

Xcode 的神奇功能:

能把非 ARC的东西统一改成ARC。

Edit->refactor->convert to objective-c ->ARC

重构 ARC

在有些第三方框架中不支持ARC的

怎么看项目是不是ARC的:

项目->build settings用放大镜 搜索auto->找编译器看object-c ARC Yes。

说明项目是ARC。

想让项目既存在ARC,有存在非ARC怎么做:

项目->build phases->comeples sourcesc4liens->选文件名.m回车 弹出方框->在

里面打上 -fno-objc->arc 敲回车。

想要项目默认不是ARC,我们想让其中某个文件是ARC,我们的做法前几个步骤相同,就

是在弹出的方框中打上 -f-objc-arc
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: