黑马程序员---OC---内存管理(在对象属性的- setter和- dealloc方法里面写内存管理代码)

------iOS培训、Java培训、Android培训, iOS学习型技术博客,期待与您交流------

内存管理(在对象属性的- setter- dealloc方法里面写内存管理代码)

内存管理范围:

任何继承自NSObject的对象;其他数据类型(int、char、double、float、struct、enum等)不需要内存管理

对象的引用计数器

每个OC对象内部都有自己的int类型(占据4个字节)的引用计数器,表示“对象被引用的次数”。

1> 当使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认为1

2> 只有当对象的引用计数器为0时,对象占用的堆内存空间才会被系统回收。

引用计数器的操作:

1> 当给对象发送一条retain消息时,可以使引用计数器的值+1(retain方法返回对象本身,该对象的引用计数器值会+1)

2> 当给对象发送一条release消息时,可以使引用计数器的值-1

3> 给对象发送一条retainCount消息可以获取当前对象的引用计数器值

对象的销毁:   - dealloc方法(不要自己调用)

1> 当一个对象的引用计数器值为0时,对象就会被销毁,其占用的堆内存空间会被系统回收

2> 当一个对象被销毁时,系统会自动向对象发送一条dealloc消息(即系统会自动调用对象的- dealloc方法,- dealloc方法相当于对象的遗言)

3> 一般会重写- dealloc方法,在重写的- dealloc方法里释放相关资源。- dealloc方法相当于对象的遗言

4> 重写- dealloc时,必须要在最后调用[super dealloc];

野指针和空指针

野指针:

指向僵尸对象(指向已经被回收的,不可用的内存)的指针

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

空指针:

OC中不存在空指针错误

[nil release];    // OC中不存在空指针错误,给空指针发送消息,不报错,相当于代码[nil  release];无效

小结:

1.方法的基本使用:

1> retain :计数器+1,返回对象本身

2> release : 计数器-1,没返回值

3> retainCount : 获取当前计数器

4> dealloc

* 当一个对象计数器为0,被回收销毁的时候,系统自动调用

* 重写dealloc方法一定要在最后调用[super  dealloc];

2.概念:

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

2> 野指针 : 指向僵尸对象(不可用内存)的指针。给野指针发送消息报错:EXC_BAD_ACCESS

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

内存管理原则:

1>

* 只要还有人在用某个对象,那么这个对象就不会被回收

* 只要你想用这个对象,就要让这个对象的计数器+1

* 当你不再使用这个对象,就让这个对象的计数器-1

2> 谁创建,谁release

* 如果你通过alloc、new或者(mutable)copy来创建一个对象,就必须调用该对象的release或autorelease

* 也就是说:如果这个对象不是你创建的,就不用你去release或者autorelease

3> 谁retain,谁release

* 只有你调用了对象的retain,最后你都要调用对象的release

总结:

1> 你想使用(占有)某个对象,就应该让该对象的计数器+1(让该对象做一次retain操作)

2> 你不想再使用(占有)某个对象,就应该让对象的计数器-1(让该对象做一次release操作)

3> 谁retain,谁release———谁alloc,谁release

/*

内存管理代码规范:

1.只要调用了alloc,必须有release(autorelease)

换言之:如果对象不是通过alloc产生的,没有调用alloc,就不能有release(autorelease)

2.set方法的代码规范:

1> 基本数据类型:直接赋值

- (void)setAge:(int)age

{

// 基本数据类型不需要管理内存

_age = age;

}

2> OC对象类型

- (void)setBook:(Book *)book

{

if (_book != book)    // 1.先判断传进来的是否为新对象

{

// 2.对旧对象(当前使用的对象)进行一次release操作

[_book release];

// 3.再对新对象做一次retain操作

_book = [book retain];    // 你想使用(占有)某个对象,就应该让该对象的计数器+1(让该对象做一次retain操作)

}

//  如果传进来的对象为原来的旧对象(_book == book)   那么什么都不做

}

3.dealloc方法的代码规范:

1> 对self(当前对象)所拥有的其他对象做一次release

2> 一定要在最后调用[super dealloc];

- (void)dealloc

{

[_book release];

[super dealloc];

}

*/

内存管理[email protected]参数

// @property参数retain : 在自动生成的set方法里,会release旧值,retain新值

// @property参数只会影响setter和getter。

@property (nonatomic, retain) Book *book;

@property (nonatomic, retain) NSString *name;

// 被retain过的属性,必须在dealloc方法中release

// dealloc方法还是要手动重写

- (void)dealloc

{

[_book release];

[_name release];

[super dealloc];

}

总结:

/* @property参数分类

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

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

* assign(默认) : 直接赋值(默认,适用于非OC对象类型,比如基本数据类型)

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

2. 是否生成set方法

* readwrite(默认) : 同时生成setter和getter的声明、实现

* readonly  : 只会生成getter的声明、实现;setter不会

3. 多线程管理

* nonatomic(推荐) : 性能高

* atomic(默认)    : 性能低

4. setter和getter方法的名称

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

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

// 返回BOOL类型的方法名一般以is开头

@property (getter = isRich) BOOL rich;

*/

用来存放数据的类叫做模型类

@class

/*

[email protected]作用:

1> 仅仅告诉编译器,某个名称是一个类的名称;能解决循环包含(#import)问题

@class Person;  // 仅仅告诉编译器,Person是一个类

2> 提高性能

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

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

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

*/

两端(对象) 循环引用(循环retain)

循环retain:A对象retain了B对象,B对象retain了A对象

会导致A对象和B对象永远无法释放

解决方案:

1> 一端用retain

2> 另一端用assign

内存管理-autorelease

/*  以前创建自动释放池对象的方式

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];    // 等价于 @autoreleasepool{

Person *p = [[[Person alloc] init] autorelease];   // 调用autorelease方法将p放入当前(栈顶)释放池中

[pool release];                                                // 等价于 }

*/

/*

错误写法:

1> alloc之后调用autorelease,-----又调用release(野指针错误)

2> 连续调用多(n)次autorelease,-------在自动释放池被销毁时,会对该对象做(n)次release操作(野指针错误)

自动释放池子:

1> 在iOS程序运行过程中,会创建无数个自动释放池。这些池子都是以栈结构存在(后进先出(后创建的先销毁))

2> 当一个对象调用autorelease方法时,系统会将这个对象放到栈顶的释放池

*/

// 自动释放池作用:延迟了存放在释放池里面对象的释放时间

// 好处:不用再关心对象释放的时间---不用再关心什么时候做release操作

// 缺点:不能精确的控制对象的销毁时间(因此适用于占用内存较小的对象);占用内存较大的对象不宜使用autorelease

@autoreleasepool

{  // @autoreleasepool{  代表创建了一个自动释放池对象

Person *p = [[Person alloc] init];    // 此行代码并未将Person对象p放入释放池中

// autorelease方法返回该对象本身

// autorelease会将对象放入一个自动释放池(对象)中

// 调用完autorelease方法后,对象计数器不变

// 当自动释放池(也是个对象)被销毁时,会对池子里面的所有对象做一次release操作

[p autorelease];  // 此时将p放入释放池中  上面两句等价于 Person *p = [[[Person alloc] init] autorelease];

@autoreleasepool    // 自动释放池对象可以创建无限个,可以嵌套创建---多个释放池对象以栈形式存放:后进先出(后创建的先销毁)

{

// 调用完autorelease方法后,对象计数器不变。  p2计数器 1

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

}

// 过了上面一行代码,p2计数器 0   p2对象被回收

}  // }代表销毁释放池,此时系统会自动对释放池里面的所有对象自动做一次release操作

#import "Person.h"

/* 总结:

1.系统自带的方法名(以类名开头,不包括前缀)里面没有包含alloc、new、copy,说明返回的对象都是autorelease好了的

2.开发中经常提供一些类方法(以类名开头),快速创建返回一个已经autorelease过的对象

1> 创建对象时不要直接用类名,一般用self

// 自定义一个类方法(以类名开头),快速创建一个已经autorelease好了的对象

+ (id)person

{

return [[[self alloc] init] autorelease];   // 尽量使用self,那样也可以满足继承自它的子类

}

*/

@implementation Person

// 自定义一个类方法(以类名开头),快速创建一个已经autorelease好了的对象

+ (id)person

{

return [[[self alloc] init] autorelease];   // 尽量使用self,那样也可以满足继承自它的子类

}

// 自定义一个类方法(以类名开头),快速创建一个已经autorelease好了的,同时初始化了的对象

+ (id)personWithAge:(int)age

{

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

Person *p = [self person];     // 尽量使用self,那样也可以满足继承自它的子类

p.age = age;

return p;

}

@end

时间: 2024-08-09 01:07:41

黑马程序员---OC---内存管理(在对象属性的- setter和- dealloc方法里面写内存管理代码)的相关文章

黑马程序员---OC基础2【对象储存】【函数和方法的区别】【方法和对象关系】【对象作为方法参数】【NSString类介绍】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- [对象储存] 1.对象的储存细节 [Car  new] new做了3件事 1)向计算机申请存储空间 2)给类中的每一个成员初始化值 3)返回新申请的空间的首地址 (1).申请的空间在内存的哪个区? new 的时候申请的空间内存的堆区(程序动态分配的内存空间) 当new内存的布局: 初始化的时候: 如果实例变量是基本数据类型,此时给初始为0, 如果是字符串类型此时初始化为null (2).实例变

黑马程序员-OC内存管理 @property的增强

涉及到内存管理,只读,多线程等很多功能时,setter和getter方法也就没那么简单了:当然@property依然强大,很好用: 1:内存管理相关参数: *:retain:  (如果是oc对象类型),生成的setter会自动release旧值,retain新值: *:assign:(适用于非oc对象)  这个是默认的值 *:copy:release旧值,copy新值: @property (retain) NSString *name; // 同类型的参数不能同时写 // @property

黑马程序员-OC特有语法:分类category,给NSString增加方法计算字符串中数字的个数

1:分类的使用场景:想对一个类,扩充一些功能,而又不改变原来类的模型,也不用继承,这时OC中的特有语法:分类可以做到: 当然分类也是一个类,也需要声明和实现,声明在.h文件中,实现在.m文件中,格式如下 // 声明 @interface  类名  (分类名称) @end // 实现 @implementation 类名 (分类名称) @end 2:分类的好处,当一个类比较庞大时,不同的部分可以放到不同的分类中,也方便团队中类的开发: 3:分类使用注意: a:分类不能增加成员变量,只能对原类增加方

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

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 手动内存管理 *为什么要学习内存管理? ①由于移动设备的内存极其有限,所以每个APP所占的内存也是有限制的. ②当我们对Objective-C 的内存管理机制琢磨不透时,编写的程序经常内存泄漏或崩溃. ③当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间. *Object-C内存管理范围 只管理任何继承了NSObject的对象,不管理其他基本数据类型(int.

黑马程序员— OC内存管理

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 之前我们学习过C语言的内存剖析,对于iOS移动设备开发来说,内存是极其有限的,因此管理好内存是相当重要的当移动设备的程序占用太多内存无法释放,有可能就会导致我们平时经常会遇到的闪退现象,这时就需要回收一些不需要再使用的内存空间,比如不需要使用的对象或者变量. 管理范围:任何继承NSObject的对象,对其他的基本数据类型(int.char.float.double.struct.enum等)无

黑马程序员-oc对象的内存管理

oc没有java的垃圾回收机制,所以对象的内存释放很重要,基本数据类型,我们不用理会,编译器会处理: oc的每个对象内部都由一个计数器,用来记录当前有几个指针在指向该对象:当计数器为0时该对象会从内存中释放: 相关方法和概念: 1:retain:对象方法,调用该对象方法,计数器+1,有返回值,返回对象本身: 2:release:没有返回值,计数器-1: 3:retainCount:获取当前计数器的值: 4:dealloc:当对象被回收时,就会调用该方法,覆盖该方法时一定要调用[super dea

黑马程序员-OC学习笔记之ARC

---------------------- IOS开发.Android培训.期待与您交流! ----------------------一.什么是ARC        ARC是自动引用计数,苹果官方在Xcode4.2及以后版本中加入的一个内存管理机制,完全取代了程序员人工的内存管理,使得程序员只须关心程序本身.使用ARC,编译器会自动在代码中加入内存管理代码,是一个编译器特性,而不是运行时特性,当然,它也和JAVA的垃圾回收不同,它的本质和手动的内存管理是一样的,只是这些代码编译器会自动添加.

黑马程序员——OC学习笔记—— Copy

黑马程序员——OC学习笔记—— Copy ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- copy 即对象拷贝 要使用对象数据而不希望修改对象时,可以使用copy copy叫做浅拷贝  mutablecopy深拷贝 copy需要遵守NSCopying协议,实现CopywithZone方法 MutableCopy也一样要遵守相应协议 注意: OC中copy复制的对象都是不可变的  mutablecopy复制的是可变副本 浅拷贝:只拷贝地址,不

黑马程序员-OC学习笔记之autorelease与自动释放池

---------------------- IOS开发.Android培训.期待与您交流! ---------------------- 一.autorelease autorelease与release相似,是OC中的一个对象方法.这两个方法都能把对象的引用计数器减1,但是release是一个精确的减1,对对象的操作只能在release之前进行,如果是在之后,就会出现野指针错误:而autorelease是一个不精确的引用计数器减1,当给对象发送autorelease消息时,对象就会被放到自动