自动引用计数

1.1 什么是自动引用计数

自动引用计数是指内存管理中对引用采取自动计数的技术

 

1.2 内存管理/引用计数

生成并持有对象:alloc/new/copy/mutableCopy

持有对象:retain

释放对象:release

废弃对象:dealloc

 

自己生成的对象,自己所持有:

id obj = [[NSObject alloc] init]; // 指向 生成并持有对象的指针 被赋值给变量obj

非自己生成的对象,自己也能持有:

id obj = [NSMutableArray array]; // 取得的对象存在,但自己不持有对象  NSMutableArray类对象被赋值给obj,但变量obj自己并不持有该对象

[obj retain]; // 使用retain方法可以持有对象

不在需要自己持有的对象时释放:

id obj = [[NSObject alloc] init]; // 自己生成并持有对象

[obj release]; // 释放对象

用某个方法生成对象,并将其返回给该方法的调用方:

- (id) allocObject {

    id obj = [[NSObject alloc] init];

    return obj;

}

原封不动地返回用alloc方法生成并持有的对象,就能让调用方也持有该对象。

调用[NSMutableArray array]使取得的对象存在,但自己不持有对象:

- (id)object {

   id obj = [[NSObject alloc] init];

   [obj autorelease];

   return obj;

}

使用了autorelease方法,可以使取得的对象存在,但自己不持有对象。

release:立即释放

autorelease:不立即释放,注册到autoreleasepool中,pool结束时自动调用release方法

无法释放非自己持有的对象:

id obj = [NSObject object]; // 取得的对象存在,但自己不持有对象

[obj release]; // 释放非自己持有的对象,应用程序崩溃

 

苹果采用散列表(引用计数表)来管理引用计数

引用计数表各记录中存有内存块地址,可从各个记录追溯到各对象的内存块

 

1.3 ARC规则

id obj = [[NSObject alloc] init]; // id 和  对象类型在没有明确指定所有权修饰符时,默认为__strong修饰符 等同于 id __strong obj = [[NSObject alloc] init];

ARC:

{

  id __strong obj = [[NSObject alloc] init];

}

// 此源代码明确指定了C语言的变量的作用域

MRC:

{

  id obj = [[NSObject alloc] init];

  [obj release];

}

// 为了释放生成并持有的对象,增加了 release 方法;该源代码进行的动作同ARC的动作完全一样

附有__strong修饰符的变量obj在超出其变量作用域时,即在该变量被废弃时,会释放其被赋予的对象

{

  // 自己生成并持有对象

  id __strong obj = [[NSObject alloc] init];

}

 // 因为变量obj超出其作用域,强引用失效,所以自动地释放自己持有的对象

通过__strong 修饰符,不必再次键入retain或者release,完美地满足了“引用计数内存管理的思考方式”:

    自己生成的对象,自己所持有

    非自己生成的对象,自己也能持有

    不再需要自己持有的对象时释放

    非自己持有的对象无法释放

 

@interface Test : NSObject

{

    id __strong obj_;

}

- (void)setObject:(id __strong)obj;

@end

@implementation Test

- (id)init

{

   self = [super init];

   return self;

}

- (void)setObject:(id __strong)obj 

{

   obj_ = obj;

}

@end

循环引用:

{

   id test0 = [[Test alloc] init]; // 对象A   test0持有Test对象A的强引用

   id test1 = [[Test alloc] init]; // 对象B   test1持有Test对象B的强引用

   [test0 setObject:test1]; // 对象A的obj_成员变量持有对象B的强引用 

   [test1 setObject:test0]; // 对象B的obj_成员变量持有对象A的强引用

}

// test0变量超出其作用域,强引用失效,所以自动释放对象A

// test1变量超出其作用域,强引用失效,所以自动释放对象B

// 此时,持有对象A的强引用的变量为  对象B的obj_ ; 持有对象B的强引用的变量为 对象A的obj_

// 发生内存泄漏

// 循环引用很容易发生内存泄漏 <内存泄漏就是应当废弃的对象在超出其生存周期后继续存在>

__weak 修饰符提供弱引用,弱引用不能持有对象实例

id __weak obj = [[NSObject alloc] init]; // 编译器对此会给出警告⚠️

// 此源代码将自己生成并持有的对象赋值给附有__weak修饰符的变量obj。即变量obj持有对持有对象的弱引用。因此,为了不以自己持有的状态来保存自己生成并持有的对象,生成的对象会立即被释放

 

id __unsafe_unretained obj = [[NSObject alloc] init]; // ⚠️

__unsafe_unretained修饰符同__weak一样,因为自己生成并持有的对象不能继续为自己所有,所以生成的对象会立即被释放

__unsafe_unretained修饰的变量既不持有对象的强引用也不持有对象的弱引用

 

@autoreleasepool {

    id __autoreleasing obj = [[NSObject alloc] init];

}

posted @ 2017-04-27 15:04  阳阳阳  阅读(209)  评论(0编辑  收藏  举报