OC基础语法(五)---内存管理



一、基本原理

     什么是内存管理:

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

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

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

     

     栈:存放局部变量(调用完自动回收);

     堆:动态产生的存储空间(需手动回收)。    

二、对象基本结构

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

    

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

引用计数器的作用:

1.创建新对象,该计数器默认是 1;

2.当一个对象的引用计数器为0,就被回收,或退出程序;

3.给对象发送一条retain消息,可以引用计数器 +1;

4.给对象发送一条release消息,可以使计数器-1;

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

    

[p retain]; 引用计数器 +1。

注:retain方法返回的是对象本身。

[p release]; 引用计数器 -1。

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

        当引用计数器变为0,p为野指针,这时候再往下使用p指针就会出

        错。

报错:下一行再使用 [p release]; 时

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

此时对象已是僵尸对象,发送retain消息还是报错。

所以要将野指针清空: p = nil;

Java中有空指针错误,但OC中不存在。

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

注:方法的基本使用

1.retain:计数器+1,会返回对象本身;

2.release:计数器-1,没有返回值;

3.retainCount:获得当前的计数器值;

4.dealloc:当一个对象要被回收的时候,就会调用

               一定要在最后调用[super dealloc].要放在最后。

    

概念:

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

野指针:指向僵尸对象的指针,给野指针发送消息会报错。

空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不回报错。

多对象内存管理:

1.谁创建,谁release

如果你通过alloc、new、或者[mutable]copy来创建一个对象,那么你必须调用release或者autorelease,

换句话说,不是你创建的,就不用你去[auto]release.

2.谁retain,谁release

只要你调用了retain,无论这个对象是如何生成的,你都要调用release。

总结:

1.有始有终,有加就有减;

2.曾经让对象的计数器+1,就必须在最后让对象-1.

三、set方法内存管理

内存管理代码规范:

OC对象类型,应当要严谨点:例如

- (void)setBook:(Book *)book

{

    //对当前正在使用的书(旧书)做一次release

    [_book release];

    //对新书做一次retain

    _book = [book retain];

}

最严谨的set方法:

- (void)setBook:(Book *)book

{//判断是不是新传来的对象

    If( book != _book)

    {

        [_book release];

         _book = [book retain];

     }

}

基本数据类型的set方法:

- (void)setAge:(int)age

{

   _age = age;

}

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

1.一定要[super dealloc],而且放在最后;

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

例子: - (void)dealloc

       {

          [_book release];

          [super dealloc];                                           

        }

- @property内存管理:

.retain:生成的set方法里,release旧值,retain新值

 @property (retain)Book * book;

property参数:

1.控制set方法的内存管理:

(1)retain:release旧值,retain新值(适用于oc对象);

(2)assign:直接赋值,不做任何内存管理(默认,用于非OC对象类型);

(3)copy:release旧值,retain新值。

2.是否要生成set方法:

(1)readwrite:同时生成setter和getter的声明和实现;

 (2) readonly:只会生成getter的声明和实现。

3.多线程管理:

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

 (2) atomic:性能低(默认)。

4.setter和getter的名称(不改变成员变量):

@property (getter = abc,setter = setAbc:)int age;

[p setAbc:10]; 这种用法是对的;

[p setAge:10]; 这种用法是错的;

但是: p.age = 10; 

       p.abc = 10; 

都是对的。

另:一般返回BOOL类型方法名一般以 is 开头:

@property (getter = isRich)BOOL rich;

p.rich = YES;

BOOL b = p.rich;

四、循环引用

对于循环依赖关系来说:比方说A类引用B类,B类引用A类。

这种代码编译会报错,当使用@class在两个类相互声明,就不会出现编译报错。

@class:

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

      例如: @class Card;

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

(1)在.h文件中用@class来声明类;

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

3.两端循环引用的解决方案:

(1)一端用retain;

(2)一端用assign;

用@class的好处:

1.解决循环包含;

2.提高性能,头文件不会再随着包含的文件的改变而重新编译。

@class和#import的区别:

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

      @class方式只是告诉编译器在A.H文件中 B *b 只是类的声明,具体这个类里面有什么信息,这里不需要知道,等文件真正实现的时候,才会真正去查看B类中的信息;

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

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

  

五、自动释放池

ios 5.0以后

autorelease方法:

1.会返回对象本身。

2.调用完autorelease,对象的计数器值不变,

3.会将对象放到一个自动释放池中,

4.当自动释放池被销毁时,会对池子里的所有对象做一次release操作。

@autoreleasepool

{//开始代表创建了释放池

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

 

}//结束代表了销毁释放池

autorelease的好处:

1.不用再关心对象的销毁时间;

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

autorelease的使用注意:

1.占用内存较大的对象不要随意使用autorelease;

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

错误写法:

1.alloc 之后调用了autorelease,有调用了release;

2.连续多次调用了autorelease。、

    

    自动释放池:

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

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

ios 5.0以前的释放池(已淘汰)

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

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

[pool release];//[pool drain];

一般可以为类添加一个快速创建对象的类方法:

+ (id)person

  Return [[[self alloc] init] autorelease];

}

系统有会默认自动回收的:

例如:  NSString *str = @"123";

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

    2.开发中经常会提供一些方法,快速创建一个已经autorelease过的对象;   创建对象时不要直接用类名,一般用self。

   

六、练习

/*

set方法内存管理

*/

#implement <Foundation/Foundation.h>

//CarDog类组合

#implement "Car.h"

#implement "Dog.h"

@interface Student : NSobject

  int _no; //学号

  NSString *_name; //姓名

  Car *_car; //car对象

  Dog *_dog; //dog对象

}

//方法的声明

- (void)setNo:(int)no;

- (int)no;

- (void)setName:(NSString *)name;

- (NSString *)name;

- (void)setCar:(Car *)car;

- (Car *)car;

- (void)setDog:(Dog *)dog;

- (Dog *)dog;

- (void)dealloc;

@end

@implementation Student

//方法的实现

- (void)setNo:(int)no

{

   _no = no;

}

- (int)no

{

   return _no;

}

- (void)setName:(NSString *)name

{

    //判断传进来的是不是新的对象

     if(name != _name)

   {

   //回收旧姓名

      [_name release]; 

     

  //retain新姓名

      _name = [name retain];

     

   }

}

- (NSString *)name

{

  return _name;

}

- (void)setCar:(Car *)car

{

     //判断传进来的是不是新的对象

    if(car != _car)

   {

    //回收旧车

      [_car release];

   //retain新车

    

      _car = [car retain];

     

   }

}

- (Car *)car

{

   return _car;

}

- (void)setDog:(Dog *)dog

{

      if(dog != _dog)

   {

      [_dog release];

    

      _dog = [dog retain];

     

   }

}

- (Dog *)dog

{

   return dog;

}

- (void)dealloc

{

//回收每个对象

    [_name release];

    [_car release];

    [_dog release];

    [super dealloc];

}

@end

int main()

{

//创建学生对象

    Student *stu = [[Student alloc] init];

  

//创建姓名对象

    NSString *name1 = @"rose";

//创建车子对象

Car *c1 = [[Car alloc] init];

c1.wheels = 4;

 

//c1传递给stu

stu.car = c1;

    

   stu.name  = name1; 

   

   //alloc一次,release一次

   [c1 release];

   [stu release];

   return 0;

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值