OC中引用计数的理解

基于OC中内存管理的一些理解
下面是本人的一些理解

  • 自己生成的对象,自己所持有
  • 非自己生成的对象,自己也能持有
  • 不再需要自己持有的对象时释放
  • 非自己持有的对象无法释放
对象操作 OC方法
生成并持有对象 alloc/new/copy/mutableCopy
持有对象 retain方法
释放对象 release方法
废弃对象 dealloc方法
这里解释一下release方法和dealloc方法的区别

release方法主要是在MRC下释放Foundation框架下面创建的对象,在ARC下面是系统自动的释放
dealloc方法是释放UIKit框架创建的UI界面的内存
(小弟的理解就是这样的,如果有错请大佬指点出来)

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

使用以下名称开头的方法名意味着自己生成的对象只有自己持有

  • alloc
  • new
  • copy
  • mutableCopy
/*
*自己生成并持有的对象
*/
id obj = [[NSobject alloc]init];
/*
*这样创建的对象引用计数+1
*/

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

用上述方法以外取得的对象,即alloc/new/copy/mutableCopy以外的方法获取的对象,因为非自己生成并持有,所以自己不是该对象的持有者,比如NSMutableArray类的array类方法创建的对象

/*
*取得非自己生成并持有的对象
*/
id obj = [NSMutableArray array];
/*
*源码中,NSMutableArray类对象被赋给变量obj,但变量obj自己并没有持有该对象。
*/
[obj retain];//obj对象的引用计数+1,调用retain方法之后就变为自己所持有

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

/*
*自己创建并持有的方法
*/
 id obj = [NSObject new];
/*
*当自己不需要的时候立即释放
*/
[obj release];

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

对于自身创建的对象或者持有的对象,在不使用的时候必须释放掉
倘若在程序中释放了非自己所持有的对象程序就会崩溃

id obj = [NSObject new];
[obj release];
/*
*当自身释放了再次释放之后系统就会崩溃
*/
[obj release];

ARC规则

在便以单位上,可设置ARC有效或者无效
一个应用程序可以混合ARC有效或无效的二进制形势
设置ARC有效的编译方式如下所示

  • 使用clang(LLVM编译器)3.0或以上版本
  • 指定编译器属性为“-fobjc-arc”
    当然在Xcode4.2及以上的版本默认设置的对所有的文件ARC有效
    当然MRC的内存管理方式对于ARC一样的适用,即:
  • 自己生成的对象,自己所持有
  • 非自己生成的对象,自己也能持有
  • 不再需要自己持有的对象时释放
  • 非自己持有的对象无法释放

权限修饰符

  • __strong
  • __weak
  • __unsafc_unretained
  • __autoreleasing

__strong

__strong修饰符是id类型和对象类型默认的所有权限修饰符。也就是说,以下源代码中的id变量,实际上被附加了所有权限修饰符
id obj = [[NSObject alloc]init];
id和对象类型在没有明确指定所有权限修饰符时,默认__strong修饰符,上面的源代码与以下相同
id __strong obj = [[NSObject alloc]init];
该源代码在ARC无效时的表述

/*ARC无效*/
id obj = [[NSObject alloc]init];
{
   /*
    *自己生成并且自己所持有
   */
    id __strong obj = [[NSObject alloc]init];
}
//此源码明确的指定了c语言的变量的作用域,ARC无效时,该源代码可描述如下:
/*ARC无效*/
{
   id obj = [[NSObject alloc]init];
   [obj release];
}
/*
*因为变量默认为__strong修饰,当obj超出了其作用域,强引用就会失效
*并且对象所有者不存在,因此废弃该对象
*/

以上是__strong修饰符修饰的自己创建并且自己持有的对象的源码分析
下面简单的说一下非自己生成并持有对象的源码

{
  id __strong obj = [NSMutableArray array];
}
//在NSMutableArray类的array类方法的源码中取得非自己生成并持有的对象
{
/*取得非自己生成并持有*/
 id __strong obj = [NSMutableArray array];
/*
*因为变量obj是强引用,所以自己持有
*/
}
/*
*变量obj超出了作用域,强引用失效,自己释放自己持有的对象
*/

其实附有__strong修饰符的变量之间可以相互赋值

id __strong obj0 = [[NSObject alloc]init];
id __strong obj1 = [[NSObject alloc]init];
id __strong obj2 = nill;
obj0 = obj1;
obj2 = obj0;
obj0 = nil;
obj1 = nil;
obj2 = nil;

当然,即便是OC类成员变量,也可以在方法参数上,使用附有__strong修饰符的变量

@interface Test : NSObject
{
    id __strong obj_;
}
- (void)setObject:(id __strong)obj;
@end
@implementation Test
- (instancetype)init{
    self = [super init];
    if (self) {
        
    }
    return self;
}
- (void)setObject:(id __strong)obj{
    obj_ = obj;
}
@end

正如苹果粑粑说的那样,通过__strong修饰符,不必再次键入retain和release,满足了“引用计数式管理的思考方式”

__weak

看起来好像通过__strong修饰符编译器就能完美的进行内存管理,但是遗憾的是,仅通过__strong修饰符是不能解决有些重大的问题
这里所有的重大的问题就是引用计数式内存管理中必然会发生的“循环引用”的问题


D4922A20-A7D5-4DDF-8DA5-44823F395BC3.png

例如:前面我们的带有__strong 的例子就容易发生循环引用

@interface Test : NSObject
{
    id __strong obj_;
}
- (void)setObject:(id __strong)obj;
@end
@implementation Test
- (instancetype)init{
    self = [super init];
    if (self) {
        
    }
    return self;
}
- (void)setObject:(id __strong)obj{
    obj_ = obj;
}
@end
//以下为循环引用
{
 id test0 = [Test new];//对象A
 id test1 = [Test new];//对象B
 [test0 setObject: test1];//对象A的obj_成员变量持有对象B的强引用
 [test1 setObject:test0];//对象B的obj_成员变量持有对象A的强引用
}

循环引用很容易造成内存泄漏


0C22C36C-812B-4821-8A00-973B886A7D3C.png

上面这种情况是两个相互强引用发生的内存泄漏,下面这种是自身强引用自身发生的内存泄漏

id test = [Test new];
[test setObject: test];

既然出现了这种强引用的内存泄漏,那么苹果粑粑就会解决这种内存泄漏,和__strong对应的修饰符__weak,如:
id __weak obj = [NSObject new];
变量obj上附加__weak修饰符,但是这样编译之后,编译器会发出警告
Assigning retained object to weak variable; object will be released after assignment
很显然,编译器的意思就是很容易造成提前释放,有问题就要解决
id __strong obj0 = [NSObject new];
id __weak obj1 = obj0;
这样赋值就不会出现警告
当然__weak还有一个优点,在持有某个对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态,代码如下:

        id __weak obj1 = nil;
        {
            id __strong obj0 = [NSObject new];
            obj1 = obj0;
            NSLog(@"A:obj1:%@",obj1);
        }
        NSLog(@"B:obj1:%@",obj1);

此源码执行的结果:
A:obj1:<NSObject: 0x103000db0>
B:obj1:(null)
但是有个注意事项:__weak修饰符只能用于iOS5以上及OS X Lion以上版本的应用,在iOS4以下及OS X Snow Leopard 的应用程序中可使用__unsafe _unretained 来修饰,但是对于现在来说也没有多少人在使用iOS4以下及OS X Snow Leopard版本了

__unsafe _unretained

__unsafe _unretained 和__weak是相同的,这里就不过多的讲解,但是要注意的是__unsafe _unretained是不安全的权限修饰符

__autoreleasing

ARC有效时不能使用autorelease和NSAutoreleasePool类,虽然autorelease无法直接使用,但是在ARC有效时autorelease功能是起作用的

/*ARC无效*/
NSAutoreleasePool *pool = [NSAutoreleasePool new];
id obj = [NSObject new];
[obj autorelease];
[pool drain];
  /*ARC有效*/    
@autoreleasepool {
          id __autoreleasing obj = [NSObject new];
}

指定“@autoreleasepool代码块”来替代“ NSAutoreleasePool”
另外,在ARC有效时,要通过将对象赋值给附加了__autoreleasing修饰符的变量来替代调用autorelease方法,对象赋值给附有__autoreleasing修饰符的变量等价于ARC无效时调用对象的autorelease方法,即对象被注册到autoreleasepool
换一种说话就是在ARC有效时,用@autoreleasepool块替代NSAutoreleasePool类,用附有__autoreleasing修饰符的变量替代autorelease方法,图解:


86FB4C33-7785-4D36-BFFB-605C4042E57B.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容