黑马程序员——OC基础——内存管理

来源:互联网 发布:民航论坛知乎 编辑:程序博客网 时间:2024/05/16 00:56

-----------android培训java培训、java学习型技术博客、期待与您交流!------------

移动设备的内存极其有限,每个app所能占用的内存是有限制的。当app所占用的内存较多时,系统会发出内存警告,这时就要回收一些不需要再使用的内存空间比如回收一些不需要使用的对象、变量等。内存管理就是为了及时地回收不需要的对象的,它的管理范围就是任何OC对象,不包括变量。

每个OC对象都有自己的引用计数器,是一个整数,它表示对象被引用的次数,即有多少人正在使用这个OC对象。每个OC对象内存中专门有4个字节的存储空间来存储引用计数器。

引用计数器的作用:

当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认就是1。当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。

操作引用计算器的常用方法有三个:

1、retain:引用计数器加1,返回当前对象。

2、release:引用计数器减1,没有返回值。

3、retainCount:返回引用计数器内的数值。

当引用计数器为0的时候,系统就会自动回收这个对象,并且在回收对象前会调用一次对象的dealloc方法。我们一般会重写dealloc方法去释放相关的资源,重写dealloc方法是一定要调用父类的dealloc方法,并且要把调用父类的dealloc方法放在后面。一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃,也就是野指针错误。下面我们来学习几个概念。

1、僵尸对象:所占用内存已经被回收的对象,它不可以再被调用,也不可以起死回生,也就是说它不可以再调用retain方法。

2、野指针:指向一个僵尸对象的指针。给野指针发消息会报错(EXC_BAD_ACCESS)。

3、空指针:没有指向任何对象的指针它里面存储的是nil,也就是0。给空指针发送消息不会报错。


下面我们通过代码学习单个对象的内存管理:

#import <Foundation/Foundation.h>// Person类的声明@interface Person : NSObject@property int age;@end// Person类的实现@implementation Person// 重写dealloc方法- (void)dealloc{    NSLog(@"Person对象被回收了");    [super dealloc];}@endint main(){    Person *p = [[Person alloc] init];    p.age = 18;        [p retain];        // 每个retain都要对应一个release    [p release];    // 每个alloc都要对应一个release    [p release];        return 0;}

我们要注意dealloc的重写一定要在最后调用父类的dealloc方法,每个alloc和retain方法都要对应一个release方法。

多个对象之间的内存管理如下:

#import <Foundation/Foundation.h>// Book类的声明@interface Book : NSObject@property double price;@end// Book类的实现@implementation Book- (void)dealloc{    NSLog(@"Book对象被回收了");    [super dealloc];}@end// Person类的声明@interface Person : NSObject{    // 在Person中定义一个Book类型的变量book    Book *_book;}@property int age;// book变量的set和get方法- (void)setBook:(Book *)book;- (Book *)book;@end// Person类的实现@implementation Person// book的set方法的实现- (void)setBook:(Book *)book{    // 想要拥有一个对象,就要让这个对象的引用计数器加1,也就是要调用retain方法    _book = [book retain];}- (Book *)book{    return  _book;}// 重写Person类的dealloc方法- (void)dealloc{    // 不想使用某个对象的时候就要调用它的release方法    [_book release];        NSLog(@"Person对象被回收了");        [super dealloc];}@endint main(){    Person *p = [[Person alloc] init];        Book *b = [[Book alloc] init];        p.book = b;        [b release];    [p release];        return 0;}

多个对象的内存管理重点:

1、要使用某个对象的时候就要让它的引用计数器加1。

2、不再使用某个对象的时候就要让它的引用计数器减1。

3、一个对象中有另一个对象作为它的变量时,要在调用对象的set方法中对被调用对象的引用计数器加1,在调用对象的dealloc方法中对引用计数器减1。


下面我们来对上面的代码进行简化,这是我们就要用的@property。当我们使用@property进行内存管理的时候我们就不需要再在set方法中写内存管理代码了,因为系统会自动生成。

#import <Foundation/Foundation.h>// Book类的声明@interface Book : NSObject@property double price;@end// Book类的实现@implementation Book- (void)dealloc{    NSLog(@"Book对象被回收了");    [super dealloc];}@end// Person类的声明@interface Person : NSObject@property (nonatomic, assign)int age;@property (nonatomic, retain)NSString *name;@property (nonatomic, retain)Book *book;@end// Person类的实现@implementation Person// 重写Person类的dealloc方法- (void)dealloc{    [_name release];    [_book release];    NSLog(@"Person对象被回收了");    [super dealloc];}@endint main(){    Person *p = [[Person alloc] init];        Book *b = [[Book alloc] init];    Book *b1 = [[Book alloc] init];        p.book = b;    p.book = b1;        [b1 release];    [b release];    [p release];        return 0;}

@property关键字有很多用途,它的小括号内的参数可以是下面的几种。

 1.set方法内存管理相关的参数

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

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

  copy   : release旧值,copy新值

 2.是否要生成set方法

  readwrite : 同时生成settergetter的声明、实现(默认)

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

 3.多线程管理

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

  atomic    : 性能低(默认)

 4.settergetter方法的名称

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

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


当两个对象之间相互引用时,我们就要一个用retain参数,一个用assign参数。


下面我们学习autorelease。autorelease也就是自动释放的意思。autorelease的作用是:

1、给某个对象发送一条autorelease消息时,就会将这个对象加到一个自动释放池中。

2、当自动释放池销毁时,会给池子里面的所有对象发送一条release消息。

3、调用autorelease方法时并不会改变对象的计数器,并且会返回对象本身。

4、autorelease实际上只是把对release的调用延迟了,对于每一次autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用Release。

autorelease的创建:

@autoreleasepool {        Person *p = [[[Person alloc] init] autorelease];    }

自动释放池的注意点:

一般来说,除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。比如说下面的例子它们返回的对象就已经是autorelease的了。

NSString *s = [NSStringstringWithFormat:@"jack"];

NSString *s2 = @"rose";


以上就是内存管理的简要介绍。

总结:

1、OC中是需要进行内存管理的,内存管理的范围是任何OC对象。

2、有alloc就一定要有release,有retain就一定要有release。

3、引用计数器占用四个字节,它是用来表示对象被引用的次数的,如果为0系统就会自动释放内存。

4、对象引用另一个对象的时候,要在set方法里面写该对象的retain,在dealloc中写上该对象的release。

5、@property的参数有很多,对于基本数据类型的变量我们写上nonatomic和assign,对于OC对象我们写上nonatomic和assign。其中nonatomic是高性能的意思,它用在多线程管理上,assign是直接赋值的意思,retain是release旧值,retain新值的意思。







0 0
原创粉丝点击