OC--内存管理

来源:互联网 发布:前锦网络信息技术校招 编辑:程序博客网 时间:2024/04/29 19:10

                                          OC--内存管理

栈:主要存储局部变量 (基本类型,指针,枚举等)

 堆:主要存储动态变量 (对象)

注意:NNString *  id是一个对象//(NNString *) name;

 什么是内存管理

      *  移动设备的内存极其有限,每个app所能占用的内存是有限制的

      *   当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等

      *   管理范围:任何继承了NSObject的对象,对其他基本数据类型(int、char、float、double、struct、enum等)无效

对象的基本结构


    *  每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象

    *  每个OC对象内部专门有4个字节的存储空间来存储引用计数器

引用计数器的作用

   *   当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1

   *  当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,

       除非整个程序已经退出

计数器方法的基本使用

1、  retain:计数器+1,会返回对象本身 [p retain];

2、  release:计数器-1,没有返回值    [p release];

3、  nil:     清空指针,使指针变为空指针p = nil;

4、  retainCount:获取当前的计数器值

5、  dealloc://类似于遗言,一般会重写

        *当一个对象要被回收的时候,就会被调用

        *一定要调用[super dealloc],这句调用要放到最后面

- (void)dealloc{/*   _speed  为成员变量  _speed  :直接访问成员变量  self -> _speed:直接访问成员变量  self .speed:get方法  self  speed:get方法*/  NSLog(@"速度为%d的Car对象被回收啦",self -> _speed);  [super dealloc ];}

概念

1、僵尸对象:所占用内存已经被回收的对象,僵尸对象不能再使用

2、野指针:指向僵尸对象(不可用内存)的指针,

给野指针发送消息会报错,错误形式为:EXC_BAD_ACCESS

3、空指针:没有指向任何东西的指针(存储的东西是nil,null,0),

          给空指针发送消息不会报错

开启僵尸对象监控

默认情况下,Xcode是不会管僵尸对象的,使用一块被释放的内存也不会报错。为了方便调试,应该开启僵尸对象监控


 对象的销毁

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

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

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

 *  一旦重写了dealloc方法,就必须调用[superdealloc],并且放在最后面调用

 *  不要直接调用dealloc方法

 *  一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)


多对象内存管理

1、你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)

2、你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)

3、谁retain,谁release   [对象 retain];    [对象 release];

4、谁alloc,谁release    [[对象 alloc] init];  最后还有dealloc

总之:一个对象有多少相关,就必须释放多少次


Set方法的内存管理

内存管理代码规范:Person对象拥有Car对象

1、  只要调用了alloc,必须有release(autorelease)

如果对象不是alloc产生的,就不需要写release

2、  set方法代码规范:

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

-  (void)setAge:(int )age{_age = age;}

2>、OC对象类型

-   (void)setCar(Car *)car{//1、先判断是不是新传进来的对象if (car != _car){//2、对旧对象做一次release[ _car release]; //3、对新对象做一次retain_car = [carretain ];}}

3、  dealloc方法的代码规范(不要自己接调用dealloc)

1>    一定要[super dealloc],而且放到最后面

2>    对self(当前)所拥有的其他对象做一次release

-  (void)dealloc{[ _car release ];[super dealloc];}

Set方法内存管理--@property的参数

格式:@peoperty (参数) 类型 名称;

1、  Set方法内存管理相关参数

       * retain:release旧值,retain新值(适用于OC对象类型)

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

        * copy:release旧值,copy新值

2、是否要生成set方法

         * readwrite:同时生成setter和getter的声明,实现(默认)

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

3、多线程管理

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

           * atomic:性能低

4、setter和getter方法的名称

           * setter:决定了set方法的名称,一定要有冒号:

          * getter:决定了get方法的名称(一般用在BOOL类型:

BOOL类型的方法名称一般以is开头)

@property的用法

@property(nonatomic,retain) 对象类型名称;一定要记得在最后的dealloc中[_名称 release]

@property(nonatomic,assign) 基本类型名称;

循环调用对象@class:@class能提高性能

1、@class的作用:仅仅告诉编译器,某个名称是一个类

@class Person; // 仅仅告诉编译器,Person是一个类

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

1>    在.h文件中用@class来声明类,写在@interface之前

2>    在.m文件中用#import来包含类的所有内容

3、  两端循环引用解决方案

一端用retain,一端用assign

4、@class和#import的区别

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

l   如果有上百个头文件都#import了同一个文件,或者这些文件依次被#improt,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了

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

@autoreleasepool {   } 自动释放池

1、  autorelease的基本用法:

1>书写形式:Book *book = [[[Bookalloc]init]autorelease];

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

2>当自动释放池销毁时,会对池子里面所有的对象做一次release

3>会返回对象本身

4>调用完autorelease方法后,对象计数器不变

 

 2、 autorelease的好处

1>    不用再关心对象释放的是时间

2>    不用再关心什么时候调用release

3、autorelease的坏处

1>    占用内存比较大的对象不要随便使用autorelease

2>    占用内存比较小的对象使用autorelease,没有太大影响

4、错误写法(野指针错误):注意

1>    在@autoreleasepool池子中,调用一次alloc,然后autorelease一次之后,

 又调用一次release

2>    在@autoreleasepool池子中,调用一次alloc,然后调用两次autorelease

  5、自动释放池

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

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

  6、自动释放池创建方式

  ios5.0后

@autoreleasepool{    // ....}

ios 5.0前

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];// .....[pool release]; // 或[pool drain];

/*

 1.系统自带的方法里面没有包含alloc、new、copy,说明返回的对象都是autorelease的

 2.开发中经常会提供一些类方法,快速创建一个已经autorelease过的对象

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

 + (id)person {    return [[[self alloc] init] autorelease]; }

ARC 编译器特性(自动生成代码)

ARC的判断准则:

1、  ARC特点:

1>    不允许调用release, retain, retainCount

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

3>    @property的参数,位置和retain一样

      *strong:成员变量强指针 (适用于OC对象类型)

      *weak:成员变量弱指针 (适用于OC对象类型)

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

4> 以前的retain 改为 strong

指针分两种:

1>    强指针:默认情况下,所有指针都是强指针 _ _strong

      * 有强指针指向的对象,ARC不会回收 

2>    弱指针:_ _weak

        *弱指针指向的对象,ARC会回收该对象,并回收掉弱指针

当两端循环引用的时候,解决方案:

1>ARC

一端用strong,另一端用weak

2>非ARC

一端用ratain,另一端用assign

 

怎么把原来不是ARC的项目改为ARC项目

1、选中项目,打开如图状态(如图 1)

                                                                                       图 1

2、然后直接点下一步,中间会有一个预览(左侧为ARC,右侧为源文件的对比)(如图 2)



                                                                                                                         图 2
3、然后点Save即可保存

怎么看项目是不是ARC

1 点击项目 (如图 3)

2 点击BuildSettings 找到放大镜

3 在放大镜里搜索Auto,显示如图1

4 然后找的Xcode对应的版本,看Object-C ARC后面,如果是Yes,则表明项目开启了ARC模式




                                                                                                                         图 3

设置文件是否用ARC

如图 4,打开到这里,具体步骤参考前面

1 点击Build Phases

2 点开下面的第二个 Compile。。。

3 选中要更改的文件,

4 按enter 打开如图小窗口,

5 在小窗口中输入对该文件的设置

( – fno-objc-arc :表示不用ARC, – fno-objc-arc :表示用ARC)



0 0
原创粉丝点击