您的位置:首页 > 职场人生

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

2015-05-17 09:50 253 查看
-----------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];
}
@end

int 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];
}
@end

int 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];
}
@end

int 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 :
同时生成setter和getter的声明、实现(默认)
  readonly  :
只会生成getter的声明、实现
 3.多线程管理
  nonatomic :
性能高 (一般就用这个)
  atomic    :
性能低(默认)
 4.setter和getter方法的名称
  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 = [NSString
stringWithFormat:@"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新值的意思。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: