-----------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -----------
一、 内存管理
OC中内存有五种
局部变量是存储在,栈内存中
动态变量存储在,堆内存中,对象就是存储在堆内存中
局部变量在运行完后,系统会自动释放,而对象不会自动释放,
设想一下,植物大战僵尸中的子弹对象,如果不及时回收,释放内存,子弹会占用非常多的内存空间
所以对象需要我们,释放其所占空间,以保障软件流畅运行。
二、 对象的释放机制
OC中我们通过引用计数器来控制对象什么时候被销毁,我们规定:当对象引用计数器值为0时,对象被回收。
当我们在创建一个对象时,他的引用计数器被赋值为1,每被赋值一次,计数器加1,当不在引用这个对象时,对象计数器减1,对象被销毁时,再减1。
我们通过retain 和 release 来实现计数器的加1,减1.
OC内存管理口诀:谁污染谁治理,alloc一下必须release一下。
Xcode6.2关闭内存管理方法:将YES改成NO,这样我们才能实现手动管理内存。ARC是OC中自动管理内存的机制,非常棒!省去我们很多时间写内存管理的重复代码。
下一章会讲到。
1、 引用计数器的基本使用
1.方法的基本使用
1> retain:计数器+1,会返回对象本身
2> release:计数器-1,没有返回值
3> retainCount:获取当前的计数器
4> dealloc
* 当一个对象要被回收的时候,就会调用
*一定要调用[super dealloc],这句调用要放在最后面
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
@end
@implementation Person
// 当一个Person对象被回收的时候,就会自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end
int main()
{
Person *p = [[Person alloc] init]; //对象被创建引用计数器加1
int a = [p retainCount]; //查看一下引用计数器的值
NSLog(@"%d", a);
//现在不用这个对象了将这个对象回收,掉用release。口诀,alloc一下,release一下。
[p release]; // 引用计数器为0,对象被回收,这时的指针就是野指针,它指向的对象就是僵尸对象
// 野指针继续调用对象方法,就会出现一些错误
[p retainCount];
// 空指针:指向没有任何对象的指针
p = nil;
return 0;
}
2.概念
1> 僵尸对象:所占用内存已经被回收的对象,僵尸对象不能再使用
2> 野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
3> 空指针:没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
三、 内存管理规范代码
1.只要调用了alloc,必须有release(autorelease)
对象只要不是通过alloc产生的,就不需要release
比如字符串对象。NSString *s = @"dymost";
2.set方法的代码规范
1> 基本数据类型:直接复制
- (void)setAge:(int)age
{
_age = age;
}
2> OC对象类型
- (void)setCar:(Car *)car
{
// 1.先判断是不是新传进来对象
if ( car != _car )
{
// 2.对旧对象做一次release
[_car release];
// 3.对新对象做一次retain
_car = [car retain];
}
}
3.dealloc方法的代码规范
1>一定要[super dealloc],而且放到最后面
2> 对self(当前)所拥有的其他对象做一次release
- (void)dealloc
{
[类中的对象 release];
[super dealloc];
}
四、 多个对象之间的内存管理
1. 非相互引用
(只是一个对象包含另一个对象)
当我们调用一个对象的时候必须retain一下,表明又有一个东西,在占用这个对象。
内存口诀:
谁retain,谁release
谁alloc,谁release
<span style="font-size:12px;">//-----------------------------车类
@interface Car : NSObject
@end
@implementation Car
// 当一个Car对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Car对象被回收");
// super的dealloc放在最后面
[super dealloc];
}
@end
//-------------------------------人类
@interface Person : NSObject
@property Car *car; //引用了Car对象,方法中需要retain一下
@end
@implementation Person
// 车的实现
-(void)setCar:(Car *)car
{
if (car != _car)
{
// 对当前正在使用的车(旧车)做一次release
[_car release];
// 对新车做一次retain操作
_car = [car retain];
}
}
// 当一个Person对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
[_car release];
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end</span>
2. 循环引用(相互引用)
其中有一方不要写内存管理方法<span style="font-size:12px;">//-----------------------------车类
@interface Car : NSObject
@property Person *owner;
@end
@implementation Car
// 人的实现
-(void)setOwner:(int *)owner
{
_owner = owner;
}
// 当一个Car对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Car对象被回收");
// super的dealloc放在最后面
[super dealloc];
}
@end
//-------------------------------人类
@interface Person : NSObject
@property Car *car; //引用了Car对象,方法中需要retain一下
@end
@implementation Person
// 车的实现
-(void)setCar:(Car *)car
{
if (car != _car)
{
// 对当前正在使用的车(旧车)做一次release
[_car release];
// 对新车做一次retain操作
_car = [car retain];
}
}
// 当一个Person对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
[_car release]; //车回收
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end</span>
五、 @property参数
与@property一样,OC给我们提供了,减少写重复代码的方法。这涉及到@property的参数。这些参数可以使系统自动帮我们生成这些内存管理代码。1、@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类型)
2、方法的重新实现
我们用这些参数来重新实现上面的两个例子1.非相互引用
<span style="font-size:12px;">@interface Car : NSObject
@end
@implementation Car
// 当一个Car对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Car对象被回收");
// super的dealloc放在最后面
[super dealloc];
}
@end
//-------------------------------人类
@interface Person : NSObject
@property (nonatomic, retain)Car *car; //引用了Car对象,方法中需要retain一下
@end
@implementation Person
// 当一个Person对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
[_car release];
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end</span>
2. 循环引用
<span style="font-size:12px;">//-----------------------------车类
@interface Car : NSObject
@property (nonatomic, assign) Person *owner;
@end
@implementation Car
// 当一个Car对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Car对象被回收");
// super的dealloc放在最后面
[super dealloc];
}
@end
//-------------------------------人类
@interface Person : NSObject
@property (nonatomic, retain)Car *car; //引用了Car对象,方法中需要retain一下
@end
@implementation Person
// 当一个Person对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
[_car release];
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end
</span>
六、autorelease
我们在创建对象的时候,每创建一个对象,后面就要写个release,当对象多了以后会显得很不方便。这时OC给我们提供了另一个方法,让我们省略release。当我们在创建对象的时候后面加上autorelease,对象就会在自动释放池中自动释放。无需我们再在后面写上release
如:
@autoreleasepool
{
Person *p2 = [[[Person alloc] init] autorelease];
}
*
1.autorelease的基本用法
1> 会将对象放到一个自动释放池中
2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3> 会返回对象本身
4> 调用完autorelease方法后,对象的计数器不变
2.autorelease的好处
1> 不用再关心对象释放的时间
2> 不用再关心什么时候调用release
3.autorelease的使用注意
1> 占用内存较大的对象不要随便使用autorelease
2> 占用内存较小的对象使用autorelease,没有太大影响
4.错误写法
1> alloc之后调用了autorelease,又调用release
@autoreleasepool
{
// 1
Person *p = [[[Person alloc] init] autorelease];
// 0
[p release];
}
2> 连续调用多次autorelease
@autoreleasepool
{
Person *p = [[[[Person alloc] init] autorelease] autorelease];
}
5.自动释放池
1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
6.自动释放池的创建方式
1> iOS 5.0前
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool release]; // [pool drain];
2> iOS 5.0 开始
@autoreleasepool
{
}
我们将上面的方法再重新实现一下,OC在很大程度上节省了我们写代码的量,将一些东西封装好,大大提高我们开发者的效率,让我们有更多的时间来思考,程序,软件的功能,结构。
<span style="font-size:12px;">#import <Foundation/Foundation.h>
//-----------------------------车类
@class Person;
@interface Car : NSObject
@property (nonatomic, assign)Person *owner;
@end
@implementation Car
// 当一个Car对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Car对象被回收");
// super的dealloc放在最后面
[super dealloc];
}
@end
//-------------------------------人类
@interface Person : NSObject
@property (nonatomic, retain)Car *car;
@end
@implementation Person
// 当一个Person对象被回收的时候,自动调用这个方法
- (void)dealloc
{
NSLog(@"Person对象被回收");
[_car release]; //车回收
// super的dealloc一定要调用,而且放在最后面
[super dealloc];
}
@end
int main()
{
@autoreleasepool {
Car *c = [[[Car alloc]init]autorelease];
Person *p = [[[Person alloc]init]autorelease];
p.car = c;
}
return 0;
}</span>
-----------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -----------
本文详细介绍了Objective-C中的内存管理,包括内存的五种类型、对象的释放机制、引用计数器的使用、内存管理规范代码如alloc与release的配合、set方法的处理、dealloc方法的注意事项,以及多个对象间的内存管理问题,特别是非相互引用和循环引用的处理。同时,还涉及了@property参数和autorelease的概念。
995

被折叠的 条评论
为什么被折叠?



