前言:OC中凡是手动建立的对象都需要我们自己管理内存,这些对象被分配到堆中。每个对象都有自己的引用计数器,如果计数器变为0,那么对象就被销毁,下面是OC中一系列关于内存方面的知识总结。
一、内存管理:
关于内存方面有几个关键词:1、retain、copy:使对象引用计数器加一;
2、release:释放一次,引用计数器减一;
3、alloc:创建新对象,默认引用技术器为一;
4、dealloc方法:当对象消亡时,会调用该方法。
例如:
<span style="font-size:18px;">#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
@implementation Person
- (void)dealloc {
NSLog(@"Person dead"); //当对象消亡,会调用这个方法
[super dealloc];
}
@end
int main() {
Person *p = [[Person alloc]init]; //这时p这个指针指向的对象默认引用计数器+1;
[p retain]; //p指向的对象引用计数器+1
[p release]; //计数器-1
[p release]; //当p指向的对象计数器为0时,对象消亡;
return 0;
}</span>
----------------------------------------------------------------------------------------------------------------------------------------------------------
二、@property参数:
先看一段代码:
<span style="font-size:18px;">#import <Foundation/Foundation.h>
@interface Dog : NSObject
@end
@interface Person : NSObject
{
Dog *_dog;
}
- (void)setDog:(Dog *)dog;
@end
@implementation Person
- (void)dealloc {
[_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
NSLog(@"Person dead"); //当对象消亡,会调用这个方法
[super dealloc];
}
- (void)setDog:(Dog *)dog {
if (dog != _dog) { //如果这条狗不是新领养的那一条
[_dog release]; //对原来那条释放
_dog = [dog retain]; //再对新狗保留所有权
}
}
@end
@implementation Dog
- (void)dealloc {
NSLog(@"Dog dead");
[super dealloc];
}
@end
int main() {
Person *p = [[Person alloc]init]; //这时p这个指针指向的对象默认引用计数器+1;
Dog *d1 = [[Dog alloc]init];
Dog *d2 = [[Dog alloc]init];
p.dog = d1; //当人第一次养狗时,需要retain一下,意味获取狗的所有权。
p.dog = d2; //人换了一条狗,那么就需要对原来那条狗释放
[d2 release];
[d1 release];
[p release]; //当p指向的对象计数器为0时,对象消亡;
return 0;
}</span>
根据例子我们知道,为了程序的严谨,我们会在set方法中加入一些代码,防止内存泄露。为了节省时间,可以为@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类型)
5、ARC补充(在下面做介绍)
strong:强指针,替换retain
weak:弱指针,相当于assign,但用于OC对象
例如:
<span style="font-size:18px;">#import <Foundation/Foundation.h>
@interface Dog : NSObject
@end
@interface Person : NSObject
@property (nonatomic, retain) Dog *dog; //会自动生成上面例子中setter的代码
@end
@implementation Person
- (void)dealloc {
[_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
NSLog(@"Person dead"); //当对象消亡,会调用这个方法
[super dealloc];
}
@end
@implementation Dog
- (void)dealloc {
NSLog(@"Dog dead");
[super dealloc];
}
@end
int main() {
Person *p = [[Person alloc]init];
Dog *d1 = [[Dog alloc]init];
Dog *d2 = [[Dog alloc]init];
p.dog = d1;
p.dog = d2;
[d2 release];
[d1 release];
[p release];
return 0;
}</span>
----------------------------------------------------------------------------------------------------------------------------------------------------------
三、循环引用:
当两个对象A包含B,B包含A时会引发循环引用,谁也不会被销毁,这时我们需要对其中一个做assign,另一个做retain
例如:
<span style="font-size:18px;">#import <Foundation/Foundation.h>
@class Person; //提前声明,告诉Dog,这个Person其实是一个类
@interface Dog : NSObject
@property (nonatomic,assign) Person *person;
@end
@interface Person : NSObject
@property (nonatomic, retain) Dog *dog; //会自动生成上面例子中setter的代码
@end
@implementation Person
- (void)dealloc {
[_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
NSLog(@"Person dead"); //当对象消亡,会调用这个方法
[super dealloc];
}
@end
@implementation Dog
- (void)dealloc {
NSLog(@"Dog dead");
[super dealloc];
}
@end
int main() {
Person *p = [[Person alloc]init];
Dog *d = [[Dog alloc]init];
p.dog = d;
d.person = p;
[d release];
[p release];
return 0;
}</span>
----------------------------------------------------------------------------------------------------------------------------------------------------------
四、autorelease:
OC会在程序运行时创建若干个自动释放池,并把它们放到一个栈中,我们可以把一个对象放到其中,当用在对象后加上autorelease时,代表它会把该对象放到栈顶的池子中。随着一个自动释放池被销毁,它会将它里面的对象做一次release操作。
例如:
<span style="font-size:18px;">#import <Foundation/Foundation.h>
@class Person; //提前声明,告诉Dog,这个Person其实是一个类
@interface Dog : NSObject
@property (nonatomic,assign) Person *person;
@end
@interface Person : NSObject
@property (nonatomic, retain) Dog *dog; //会自动生成上面例子中setter的代码
@end
@implementation Person
- (void)dealloc {
[_dog release]; //当人死亡时,把狗也杀了(太不道德了。。)
NSLog(@"Person dead"); //当对象消亡,会调用这个方法
[super dealloc];
}
@end
@implementation Dog
- (void)dealloc {
NSLog(@"Dog dead");
[super dealloc];
}
@end
int main() {
@autoreleasepool {
Person *p = [[[Person alloc]init]autorelease];
Dog *d = [[[Dog alloc]init]autorelease];
p.dog = d;
d.person = p;
} //当池子被销毁,里面的对象会做一次release操作
// [d release]; //不需要release,因为我们d与p两个对象都在自动释放池中
// [p release];
return 0;
}
</span>
注意:当我们想准确操作一个对象的“生死”时,不要把它放到自动释放池中,它只适用于小数据的自动释放。
----------------------------------------------------------------------------------------------------------------------------------------------------------
五、ARC机制:(Automatic Reference Counting)
ARC属于编译时的机制,它会检查一个对象是否有强指针指向它,如果没有,它会在后面加上release代码。这点区分于JAVA的垃圾回收机制,JAVA程序会在程序运行时检测一个对象是否有指针指向,如果没有那么就会将对象作为垃圾回收。
解释一下@property中两个参数:
1、strong:声明对象为强指针(默认)
2、weak:声明对象为弱指针,当它指向的一个对象,同时没有其他强指针指向时,会被ARC添加release代码,该对象会被回收,这个弱指针也会自动被赋值为nil,所以弱指针不能单独指向对象。
例如:
<span style="font-size:18px;">#import <Foundation/Foundation.h>
@class Person; //提前声明,告诉Dog,这个Person其实是一个类
@interface Dog : NSObject
@property (nonatomic,strong) Person *person; //retain变为strong
@end
@interface Person : NSObject
@property (nonatomic, weak) Dog *dog; //防止循环引用,assign变成weak
@end
@implementation Person
- (void)dealloc {
NSLog(@"Person dead");
}
@end
@implementation Dog
- (void)dealloc {
NSLog(@"Dog dead");
// [super dealloc ]; //这句会被报错
}
@end
int main() {
Person *p = [[[Person alloc]init]autorelease];
Dog *d = [[[Dog alloc]init]autorelease];
p.dog = d;
d.person = p;
// [p release]; //有了ARC,所有关于内存方面的关键字都不会再被使用。
// [d release];
return 0;
}</span>
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com