您的位置:首页 > 运维架构

oc的内存管理和@property的属性关键字

2015-09-28 12:02 204 查看
我们来看看内存分布

栈:存放的是局部变量,这块存储区域是系统管理的,不需要我们管理。

堆:存放的是OC中的对象,这块存储区域是程序员自己管理的。它是动态存储区域。

常量区:存放的是常量,这块存储区域是系统管理的。

全局区:存放的时全局变量和静态变量,这块存储区域是系统管理的。

代码区:存放分是代码,这块区域是系统管理的。

指针存放在栈中,而指针指向的变量是存放在堆中。因此当指针被回收的时候,它的对象并不会被回收。

MRC(Manual Reference Counting)手动内存管理|手动引用计数

在OC的内存管理中:引进了引用计数。

1、当一个对象被建立的时候,它的引用计数是1。

2、当一个对象的引用计数是0的时候,这个对象将会被回收。

引用计数

1、release 引用计数-1

2、retain
引用计数+1 (这里还会返回一个调用该方法的对象)

3、retainCount 返回当前对象的引用计数

手动内存管理黄金法则:

谁调用alloc\new\retain\copy\mutableCopy,谁就调用相应的release|autorelease;

当你需要某一个对象的时候,那么就给它发送一条retain方法。

当你不需要某一个对象的时候,那么就给它发送一条release方法。

内存管理不当产生的后果:

1、如果不再使用的对象没有被回收,就会照成内存泄露。会导致程序闪退。

2、如果正在被使用的对象被回收了,就会照成野指针错误。会导致程序崩溃。

内存管理中的关键字(@property)

retain在setter和getter方法中加入一些内存管理的代码(当属性是一个普通的OC对象的时候就使用retain)

assign表示的时直接复制,不会产生内存管理的代码(当属性是一个基本数据类型的时候就使用assign)

copy表示复制对象(当属性是NSString数据类型的时候就使用copy)

在@property中的关键字还有

生成多线程线程安全的关键字

nonatomic表示非原子的,不会生成线程安全的代码,速度比较快。iOS中的属性一般都是使用它。

atomic表示原子的,它会生成线程安全的代码。

控制权限的关键字

readonly表示可以读,只能生成getter方法。

readwrite表示可以读可以写,生成getter和setter方法的声明与实现。

修改方法名称的关键字

getter表示修改生成的getter方法的名称。一般情况下,BOOL类型的属性的getter方法都是以is开头的。

setter表示修改生成的setter方法的名称,不过一般不修改。

循环引用:

指针的是两个对象中,你中有我,我中有你。跟java中的一对一很相似。至于产生内存泄露的原因主要是相互之前强指针指着对方,感觉跟java里面谁来hibernate设置谁来管理对方。(在这里我们引入了强指针与弱指针在ARC中会提到,这里不做解释。)

解决循环引用的方式:让其中一方设置为assign。

多个对象之间不要封闭环,如果出现封闭的环,那么环中所有的对象将得不到释放。解决的方法,让其中一端为虚线。

自动释放池:(自动释放池是一个栈)

autorelease:延长对象的释放生命周期。作用:把对象放进离自己最近的那个自动释放池中。(它与对象在何地创建没有关系,只要标记上就放进离自己最近的那个自动释放池中。)

当自动释放池销毁的时候,它会把放在池中的所有对象进行一次release操作。

调用几次autorelease,在自动释放池销毁的时候就调用几次release操作。

在自动释放池中,只要是使用getter方法|构造方法返回来的对象都是放在池中。

ARC(automatic Reference Counting)自动内存管理

ARC中编译器的特性:编译器会在适当的时候,加入内存管理的代码。

(_strong强指针标识符,默认所有的指针都是强指针)

作用:只要强指针指向的对象,那么这个对象就不会被释放。

只要没有强指针指向的对象,那么这个对象将会被立即被释放。

(_weak弱指针标识符)

弱指针:不参与内存管理,对内存管理没有影响。不会影响对象的回收。

注意:不要使用一个弱指针指向一个刚刚创建出来的对象,一旦这样做,刚创建出来的对象马上销毁,在OC中也是自动销毁机制。

当出现循环引用的时候就必须要让一端使用弱指针。

在ARC中的@property

strong 对所有的普通OC对象

copy 对字符串

assign 基本数据类型

weak 对于循环应用的时候,必须保证一段使用的是weak。如果不这样你懂的。

ARC中的自动释放池机制:

只要是通过方法返回来的对象都是存放在ARC的自动释放池中。

以上的测试代码如下:

#import"Person.h"

#import "Room.h"

int main(int argc, const char *
argv[]) {

// Person *person = [[Person alloc]init];

// long count = [person retainCount];

// NSLog(@"%zd",count);

// [person retain];

// NSLog(@"%zd",[person retainCount]);

// [person release];

// NSLog(@"%zd",person.retainCount);

// [person release];

// //测试OC中有没有空指针异常(发现系统不会报错,并且什么都没做)

// person = nil;

// NSLog(@"%zd",person.retainCount);

//多对象的内存管理

Person *person = [[Person alloc]init];//1

Room *room = [[Room alloc]init];//1

[person setRoom: room];//room = 2

[room release];// room = 1

room = nil;

[person release];// person =0 room =0;

person = nil;

return 0;

}

/////////////////////////////

#import <Foundation/Foundation.h>

@class Room;

@interface Person : NSObject

@property(nonatomic,retain)Room *room;

//- (void)setRoom:(Room *)room;

@end

////////////////////////////

#import "Person.h"

#import "Room.h"

@implementation Person

//- (void)setRoom:(Room *)room{//这个跟@property(nonatomic,retain)Room *room生成的方法一致

// //成员对象一创建的时候,就会被初始化为nil

// //此处要加一个判断,判断两个对象是否是同一个对象。如果不相同,才需要内存管理的代码。

// if(_room != room){

// [_room release];

// _room = [room retain];

// }

//// [room retain];

//// _room = room;

// //等于(因为retain会返回对象)

//// _room = [room retain];

//// [_room release];

//// _room = [room retain];

//

//}

//永远不要试图自己调用这个方法

- (void)dealloc{

// [_room release];

// _room = nil;

//等价于

self.room = nil;//因为nil调用方法不会有任何变换。因此在上面的set方法中,不会让计数器加一

//它会在对象回收的时候被打印出来

NSLog(@"Person对象被回收了");

//这个方法中必须调用父类的该方法,并且必须放在最后

[super dealloc];

}

@end
/////////////////////////////

@interface Room : NSObject

@end

////////////////////////////

#import "Room.h"

@implementation Room

- (void)dealloc{

NSLog(@"Room对象被回收了");

//这个方法中必须调用父类的该方法,并且必须放在最后

[super dealloc];

}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: