<<iOS 与OS X多线程和内存管理>>笔记:ARC与所有权修饰符

注:本文为笔记形式,所以很多都是摘抄的.<<iOS 与OS X多线程和内存管理>>书中写的很棒,简单易懂,建议各位看官自己去看看.


ARC和MRC


前一篇主要是MRC环境下的引用计数,这一篇我们主要说一下ARC环境以及所有权修饰符,在Xcode4.2之后,苹果公司开始推出ARC环境,ARC会自动的帮助我们处理"引用计数"的问题,这样让iOS开发人员能够不再关注内存管理这一块,让开发人员更加注重应用的开发.在Xcode切换ARC和MRC如下图所示.


所有权修饰符说明


在ARC环境下,id类型一共有四种所有权修饰符,分别是 __strong__weak__unsafe_unrerained__autoreleasing.下面我们就分别对这四种所有权修饰符进行说明讲解.

__strong修饰符


__strong修饰符是id类型和对象类型默认的所有权修饰符,也就是说,所有对象的创建都被默认加上了__strong修饰符.

    //默认是加上了__strong修饰符
    id obj = [[NSObject alloc]init];

在ARC环境下,下面代码等同于上面代码.

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

那么在MRC中,__strong修饰符代表着什么呢?如下代码所示.

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

上面的代码好像不能很好的表达__strong修饰符在MRC环境中的所表示的意义.其实在MRC环境中,下面代码等同于上面.其中{}之间代表着变量的作用域,__strong修饰符表示对对象的"强引用",持有强引用的变量在超出作用域时被废弃,随着强引用的失效,引用的对象也随之释放.

{
    id  obj = [[NSObject alloc]init];
    [obj release];
}

上面是说的自己生成并且持有的对象,那么对于非自己生成并且持有的对象,如下代码所示.这样对象的所有者和对象的生存周期就不明确了,__strong有做了什么操作呢?这其中和MRC的手动管理对象的引用计数是一样的,当超出对象的作用域的时候,强引用会失去作用.这时候,会自动的释放自己持有的对象,如果对象的所有者都不存在了,也就是说对象的引用计数为0的时候,会废弃对象.

{
id  __strong obj = [NSMutableArray array];
}

那么,有了强引用__strong之后,为什么会出现__weak弱引用呢?这就是我们在平常开发过程中经常遇到的一个问题,循环引用,下面我们就在__weak这个修饰符中说说循环引用的出现以及解决方案.

__weak修饰符


循环引用一般分为两种情况,一种是两个对象之间相互持有;另外一种则是对象本身持有自己.我们先看一下两个对象之间相互持有,比如我们创建两个数组,然后相互添加对方,如下所示,这样就会造成内存泄漏问题.

{
NSMutableArray *firstArray=[[NSMutableArray alloc]init];
NSMutableArray *secondArray=[[NSMutableArray alloc]init];
[firstArray addObject:secondArray];
[secondArray addObject:firstArray];
}

对于内存泄漏的检测,各位看官可以查看iOS开发之内存泄漏检测工具-Leaks,我们可以使用Leaks工具检测内存泄漏.那么到底是怎么造成内存泄漏的呢?

首先,{}之间仍然代表着变量的作用域,我们在作用域创建两个数组,其中firstArray持有数组对象A,secondArray持有数组对象B,如下所示.

{
NSMutableArray *firstArray=[[NSMutableArray alloc]init];//数组对象A
NSMutableArray *secondArray=[[NSMutableArray alloc]init];//数组对象B
}

问题出现假两者的互相添加,现在通过firstArray把数组对象B添加到数组对象A中,通过secondArray把数组对象A添加到数组对象B中,这样数组对象A和B这两者就相互持有了.

[firstArray addObject:secondArray];
[secondArray addObject:firstArray];

上面的两大部分看似是没有任何问题,但是问题出现在超出作用域释放对象的时候,首先,因为firstArray持有数组对象A的强引用,secondArray持有数组对象B的强引用,两者都会自动释放,此时,数组对象A和B相互持有所以不能释放.可以理解为造成了一个死循环(A中有B,B中有A,比如释放A,那么需要把A中的B也释放掉,B中又存在着A,那么又要接着释放A,如此无限循环下去.造成不能释放).


还有一种内存泄漏的情况就是对象本身持有对象本身,情况和上面情况类似.代码如下.

{
NSMutableArray *testArray=[[NSMutableArray alloc]init];
[testArray addObject:testArray];
}

那么,OC是如何解决相互引用的,这就需要使用到__weak修饰符了,如下代码所示.

    __weak NSMutableArray  *testArray=[[NSMutableArray alloc]init];

但是这样是出现警告的,原因就是__weak修饰符是为了不以自己持有的状态来保存自己生成并且持有的对象,生成对象会被立即释放掉.这时候testArray实际上是不持有数组对象的.

这样我们就可以使用__weak修饰符来解决循环引用问题了.但是呢,根据书中所讲,__weak修饰符只能用于iOS 5以上及OS X Lion版本的程序,那么在此之前用的就是我们下一个模块要说的__unsafe_unrerained修饰符.


__unsafe_unrerained修饰符


相比于__weak__strong这两个我们常用的修饰符, __unsafe_unrerained修饰符确实已经不多见了.现在Xcode都已经是8.0+,所以,我们需要对__unsafe_unrerained修饰符有个大体的了解即可.__unsafe_unrerained修饰符是不安全的所有权修饰符,它的作用和__weak修饰符的作用类似.


__autoreleasing修饰符


我们知道在ARC环境下我们不能使用autorelease这个方法,也不能使用NSAutoreleasePool这个类,关于autorelease的使用方法请查看<<iOS 与OS X多线程和内存管理>>笔记:MRC与引用计数中的autorelease模块.使用方法如下所示.

@autoreleasepool {
    
    __autoreleasing id obj  = [[NSMutableArray  alloc]init];
}

上面的代码等同于在MRC环境下的如下代码.

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    
id obj  = [[NSMutableArray  alloc]init];
[obj autorelease];
    
[pool drain];

那么 __autoreleasing修饰符在我们实际开发过程中是怎么使用的呢?其中,被__weak修饰过的对象实际上必定要访问注册到autoreleasepool的对象.这是为什么呢?我们知道被__weak修饰过的对象只持有对象的弱引用,而在访问引用对象的过程中,该对象有可能被废弃.如果把要访问的对象注册到autoreleasepool中,那么@autoreleasepool块结束之前,我们都能访问到该对象.所以被__weak修饰过的对象实际上必定要访问注册到autoreleasepool的对象.示例代码如下所示.

@autoreleasepool {
    
    id obj = [[NSObject alloc]init];
    __weak id obj1  = obj;
    __autoreleasing  id tmp = obj1;
 
}


尾声


笔记将继续进行下去,欢迎大家一起来讨论<<iOS 与OS X多线程和内存管理>>相关问题,如果有任何问题,欢迎联系骚栋,谢谢.最后还是<<iOS 与OS X多线程和内存管理>>的pdf版的下载传送门,各位看官可以自行去参考查看.

<<iOS 与OS X多线程和内存管理>>的pdf版传送门🚪


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

推荐阅读更多精彩内容

  • 简介 strong/retain:只能修饰对象。持有对象。两者等价。 assign/unsafe_unretain...
    xuyafei86阅读 2,890评论 0 3
  • 概述 在iOS中开发中,我们或多或少都听说过内存管理。iOS的内存管理一般指的是OC对象的内存管理,因为OC对象分...
    DamonMok阅读 3,980评论 2 20
  • 貌似每个iOS开发者都有一篇属于自己的内存管理,记录了自己对内存管理理解的深度以及广度,所以我也来记录一下我的理解...
    Bugfix阅读 2,248评论 0 3
  • 是什麼樣的風雨 讓靈魂有了滋養的泥土 我們不缺所有的成長技能 卻苦無向著天堂的階梯 一直漂泊在茫茫人海 我們似乎看...
    蔡振源阅读 591评论 2 9
  • 站在2016年最后的几分钟里,插着耳机,耳中单曲循环着汪峰的《春天里》。 《春天里》是一首非常不错的哥,我总过听过...
    荒岛牧羊阅读 203评论 0 0