1.引用计数
ios内存管理采用引用计数方式,举个最简单的例子:
1.把内存比喻成房子,人是一个对象
2.假设有A,B,C,D四人依次进入房子,和依次退出房子
3.现有逻辑为开灯生成对象,需要照明持有对象,不需要照明释放对象,关灯废弃对象
4.A进入房子并开灯(计数为1)-->B进入房子,由于房间已开灯无需再次开灯(计数加1)-->C进入房子,由于房间已开灯无需再次开灯(计数加1)-->D进入房子,由于房间已开灯无需再次开灯(计数加1)
5.A退出房子,由于房间有人,无需关灯(计数减1)-->B退出房子,由于房间有人,无需关灯(计数减1))-->C退出房子,由于房间有人,无需关灯(计数减1)-->D退出房子,房间无人,关灯(计数为0)
2.思考方式
内存管理思考方式有四种
1.自己生成的对象自己持有(alloc/new/copy/mutablecopy)
2.非自己生成的对象自己也能持有(retain)
3.不需要自己持有的对象释放(release)
4.非自己持有对象无法释放(delloc)
3.所有权修饰符
__strong 强引用,对象和id的默认修饰符,当其持有对象超出变量域时候,强引用失效,会自动释放对象
{
id __strong obj0 = [[NSObject alloc]init];//obj0持有对象A
id __strong obj1 = [[NSObject alloc]init];//obj1持有对象B
obj0 = obj1;//obj1值赋给obj0,obj0持有对象B 对象A强引用失效,对象A被废弃
}
关于__strong使用弊端,循环引用导致内存泄漏
@interface ObjectTest : NSObject{
id __strong objA;
}
-(void)setObject:(id __strong)obj;
@end
@implementation ObjectTest
-(void)setObject:(id __strong)obj{
objA = obj;
}
定义一个带有强引用的对象
{
id __strong test0 = [[ObjectTest alloc]init];//test0持有对象A
id __strong test1 = [[ObjectTest alloc]init];//test1持有对象B
[test0 setObject:test1];//objA 持有对象B test1持有对象B
[test1 setObject:test0];//objA 持有对象A test0 持有对象A
}
//当test0 和test1 强引用失效时 A B都被释放,但 objA还是持有A 和B的强引用,这时候内测泄漏
当只定义一个对象时,也会发生循环引用,但是这时候强引用的对象是它自己,这时候我们就需要weak来避免循环了
__weak 不持有强引用对象,当某对象弱引用的时候,如果该对象被废弃,弱引用自动失效并被置空
id __weak test1 = nil;
{
id __strong test0 = [[ObjectTest alloc]init];
test1 = test0;
NSLog(@"test0=%@",test0);
}
NSLog(@"test1=%@",test1);//超出作用域自动置空
__unsafe _unretained 不安全修饰符,在IOS4之前使用
__autoreleasing 当指针没有显示指定修饰符的时候用的就是__autoreleasing 比如之前的id obj 等同于 id __strong obj 但是id *obj 等同于 id __autoreleasing *obj