OC语言-05-OC语言-内存管理

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

一、引用计数器

1> 栈和堆

栈

① 主要存储局部变量

② 内存自动回收

堆

① 主要存储需要动态分配内存的变量

② 需要手动回收内存,是OC内存管理的对象

2> 简介

作用

① 表示对象被引用的次数

② 通常由alloc、new、copy与release方法引发

③ 动态监测引用计数器的值,当值为0时回收对象所占的内存

使用注意

① 引用计数器一个NSUInteger类型的变量,占用4字节内存

② 在对象被创建的时候引用计数器的值被初始化为1

③ 每个使引用计数器加1的操作,都有一个引用计数器减1的操作与之

对应

3> 基本概念

僵尸对象

① 所占用的内存已经被回收的对象

② 僵尸对象不能再被使用

野指针

① 指向僵尸对象的指针

② OC中引用野指针会报错,错误信息:EXC_DAB_access

空指针

① 没有指向任何内存地址的指针

② 空指针的值通常为nil、NULL或0

③ 通常在创建指针时将其初始化,避免其指向不确定的内存

④ 在对象被销毁后,通常要将指向对象的指针赋值为nil,避免产生野

指针

4> 基本方法

retain

① 使引用计数器加1

② alloc、new、copy等方法会自动调用retain方法

③ 每个retain方法都必须对应一个release方法

④ 返回值为对象本身

release

① 使引用计数器减1

② 没有返回值

③ 用空指针调用release方法不会报错

④ 不是经过alloc方法创建的对象,不需要执行release操作

dealloc

① 在对象被销毁时调用

② 通常需要重写dealloc方法

③ 重写dealloc方法时,必须在最后调用父类的dealloc方法

④ @PRoperty不会影响dealloc方法,只会影响色图特人和getter

二、多对象内存管理

1> 基本使用

当拥有某个对象时,就对该对象执行retain操作

当抛弃某个对象时,就对该对象执行release操作

谁执行retain操作,谁就执行release操作2> set方法的内存管理

基本使用

① 当set方法的参数是OC对象时,通常要在set方法内实现内存管理

② 当参数与成员变量不一样时,才对成员变量执行release操作,对

参数执行retain

set方法的代码规范

① 基本数据类型:直接赋值

② OC对象类型

1)先判断是不是新对象

2)若是,对就对象执行一次release操作,对新对象执行一次retain

操作

3)否则,不执行操作

dealloc方法的代码规范

① 对self拥有的所有对象执行一次release操作

② 一定要调用父类的dealloc方法,且放在最后

③ 在ARC环境下重写dealloc方法不能调用父类的dealloc方法

3> @property对内存的影响

基本使用

① 为成员变量生成setter和getter

② 默认生成的setter执行的是直接赋值,不涉及内从管理

③ 若setter的参数是OC对象,需要设置@property的参数,使其生成

内存管理代码

@property的参数

① 内存管理相关参数

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

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

3)copy:release旧对象,copy新对象

② 控制成员变量属性的参数

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

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

③ 多线程管理相关参数

1)nonatomic:生成setter方法时不加线程管理代码,性能高

(一般用这个)

2)atomic:生成setter方法时加上线程管理代码,性能低(默认)

④ 指定setter和getter名称的参数

1)通过setter指定生成的set方法的名称,通过getter指定生成的

get方法的名称

2)不影响点语法的使用,点语法在使用时先转换为对应的set或get

方法

3)通常当get方法的返回值为BOOL类型数据时,对get方法使用,

set方法几乎不用

4> 循环包含与循环引用

循环包含

① 但两个类的声明文件循环包含时,通常要在一个文件中用@class

声明另一个类

② 使用规范

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

2)在.m文件中用#import包含类的声明文件

循环引用

① 当两个OC类循环引用时,会产生内存管理问题

② 解决方法

1)在一个类的声明中,指定@property的内存管理参数为retain

2)在另一个类的生命中,指定@property的内存管理参数为release

三、autorelease

1> 基本使用

作用

① 将调用该方法的对象放进自动释放池,当池子销毁时,对池子内所有

的对象执行一次release操作

② 通常在对象创建时调用,放回对象本身

自动释放池的创建方式

① 通过@autoreleasepool{}创建

② 通过NSAutoreleasePool类创建

2> 使用注意

自动释放池的创建和释放遵循栈规则

调用autorelease方法不会对引用计数器产生影响

autorelease方法延迟了对象的释放时间,占用内存较大的对象不要使用

一个对象不能多次调用autorelease方法

一个对象不能同时使用autorelease方法和release方法3> 常见应用

快速创建一个自动释放池内的对象

① 通常设计一个类方法,快速创建一个自动释放池内的对象

② 方法名通常以类名开头

③ 创建时要使用self调用alloc、init与autorelease方法,不要使用类名

四、ARC

1> 基本使用

强指针与弱指针

① 强指针

1)通过__strong声明的指针

2)所有的指针默认都是强指针

② 弱指针

1)通过__weak声明的指针

2)当弱指针指向的对象被释放,弱指针将被清空

判断准则

只要没有强指针指向对象,对象就会被释放

2> @property的strong和weak参数

strong参数相当于retain参数

weak参数相当于assign参数3> 循环引用的解决方法

将 at property一端的参数指定为strong

将 at property另一端的参数指定为weak五、示例(多文件)

/*

1.创建一个Person类和一个Dog类,Person类与Dog类是相互用有关系

2.重写Person类与Dog类的dealloc方法

3.重写Person类的set方法,实现内存管理代码

4.自定义Person类构造方法,用于快速创建一个自动释放池内的Person对象

*/

/*****main.m文件******/

#import <Foundation/Foundation.h>

//包含Person类的声明文件

#import "Person.h"

//包含Dog类的声明文件

#import "Dog.h"

int main()

{

//创建自动释放池

@autoreleasepool {

//创建Dog对象,并加入到自动释放池中

Dog *d = [[[Dog alloc] init] autorelease];

/*通过调用类方法快速创建一个Person类型的自动释放池对象

并用Dog初始化新创建的对象的成员变量*/

Person *p = [Person personWithDog:d];

//将指针清空

p = nil;

}

return 0;

}

/*****Person.h文件******/

#import <Foundation/Foundation.h>

//声明Dog是一个类,Dog.h文件用#import指令

@class Dog;

@interface Person : NSObject

/*通过@property生成dog属性的getter和setter

并使用参数retain,Dog.h使用assign参数*/

@property (nonatomic, retain) Dog *dog;

/*自定义方法,快速创建一个Person类型的自动释放池对象,

并用Dog初始化新创建的对象的成员变量*/

+ (Person *)personWithDog:(Dog *)dog;

@end

/*****Person.m文件******/

#import "Person.h"

//使用@class声明的类,在实现文件中要用#import指令包含该类的头文件

#import "Dog.h"

@implementation Person

+ (id)personWithDog:(Dog *)dog

{

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

//将dog赋值给新创建对象的成员变量

p.dog = dog;

return p;

}

//重写dealloc方法

- (void)dealloc

{

NSLog(@"Person对象被释放");

//释放person所拥有的属性

[_dog release];

//调用父类的dealloc方法

[super dealloc];

}

@end

/*****Dog.h文件******/

#import <Foundation/Foundation.h>

//包含Person.h头文件,Person.h文件用@class指令

#import "Person.h"

@interface Dog : NSObject

/*通过@property生成person属性的getter和setter

并使用参数retain,Person.h使用retain参数*/

@property (nonatomic, assign) Person *person;

@end

/*****Dog.m文件******/

#import "Dog.h"

@implementation Dog

//重写dealloc方法

- (void)dealloc

{

NSLog(@"Dog对象被释放");

//释放Dog所拥有的属性

[_person release];

//调用父类的dealloc方法

[super dealloc];

}

@end

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航