哪位兄弟哪位高人来帮我看看看登cf这情况怎么解决

******************************更新复联2,蚁人,美队3,2016年9月6日!期待《奇异博士》,《银护2》,《蜘蛛侠:归来》,《雷神3:诸神黄昏》《黑豹》《复仇者联盟3:无限战争》《蚁人与黄蜂女》《惊奇队长》!!!!!!!!!!!*********************…

本文来源于我个人的ARC学习笔记,旨在通过简明扼要的方式总结出iOS开发中ARC(Automatic Reference Counting,自动引用计数)内存管理技术的要点,所以不会涉及全部细节。这篇文章不是一篇标准的ARC使用教程,并假定读者已经对ARC有了一定了解和使用经验。详细的关于ARC的信息请参见苹果的与网上的其他教程:)


ARC是编译器(时)特性,而不是运行时特性,更不是垃圾回收器(GC)。

在ARC引入后,没有了retain和release等操作,情况也发生了改变:在任何情况下,__block修饰符的作用只有上面的第一条:说明变量可改。即使加上了__block修饰符,一个被block捕获的强引用也依然是一个强引用。这样在ARC下,如果我们还按照MRC下的写法,completionHandler对myController有一个强引用,而myController对completionHandler有一个强引用,这依然是循环引用,没有解决问题:(

于是我们还需要对原代码做修改。简单的情况我们可以这样写:

这样循环引用的问题就解决了,但是却不幸地引入了一个新的问题:由于传入completionHandler的是一个弱引用,那么当myController指向的对象在completionHandler被调用前释放,那么completionHandler就不能正常的运作了。在一般的单线程环境中,这种问题出现的可能性不大,但是到了多线程环境,就很不好说了,所以我们需要继续完善这个方法。

到此,一个完善的解决方案就完成了:)

官方文档对这个问题的说明到这里就结束了,但是可能很多朋友会有疑问,不是说不希望Block对原myController对象增加强引用么,这里为啥堂而皇之地在Block内新定义了一个强引用,这个强引用不会造成循环引用么?理解这个问题的关键在于理解被Block捕获的引用和在Block内定义的引用的区别。为了搞得明白这个问题,这里需要了解一些Block的实现原理,但由于篇幅的缘故,本文在这里就不展开了,详细的内容可以参考其他的文章,这里特别推荐和另外2位作者的博文:和,讲的都比较清楚。

这里假设大家已经对Block的实现原理有所了解了。我们就直入主题了!注意前方高能(=。=)

为了更清楚地说明问题,这里用一个简单的程序举例。比如我们有如下程序:

程序中,同为int型的指针,a是被Block捕获的变量,而c是在Block内定义的变量。我们用clang -rewrite-objc处理后,可以看到如下代码:

我们可以清楚得看到,a和c存在的位置完全不同,如果Block存在于堆上(在ARC下Block默认在堆上),那么a作为Block结构体的一个成员,也自然会存在于堆上,而c无论如何,永远位于Block内实际执行代码的函数栈内。这也导致了两个变量生命周期的完全不同:c在Block的函数运行完毕,即会被释放,而a呢,只有在Block被从堆上释放的时候才会释放。

回到我们的MyViewController的例子中,同上理,如果我们直接让Block捕获我们的myController引用,那么这个引用会被复制后(引用类型也会被复制)作为Block的成员变量存在于其所在的堆空间中,也就是为Block增加了一个指向myController对象的强引用,这就是造成循环引用的本质原因。对于MyViewController的例子,Block的结构体可以理解是这个样子:(准确的结构体肯定和以下这个有区别,但也肯定是如下这种形式:)

再看在Block内声明的强引用strongMyController,它虽然是强引用,但存在于函数栈中,在函数执行期间,它一直存在,所以myController对象也一直存在,但是当函数执行完毕,strongMyController即被销毁,于是它对myController对象的强引用也被解除,这时Block对myController对象就不存在强引用关系了!加入了strongMyController的函数大体会是这个样子:

综上所述,在ARC下(在MRC下会略有不同),Block捕获的引用和Block内声明的引用无论是存在空间与生命周期都是截然不同的,也正是这种不同,造成了我们对他们使用方式的区别。

以上就解释了之前提到的所有问题,希望大家能看明白:)

好的,最后再提一点,在ARC中,对Block捕获对象的内存管理已经简化了很多,由于没有了retain和release等操作,实际只需要考虑循环引用的问题就行了。比如下面这种,是没有内存泄露的问题的:

我们上面提到的解决方案,只是针对Block产生循环引用的问题,而不是说所有的Block捕获引用都要这么处理,一定要注意!


Toll-Free Briding保证了在程序中,可以方便和谐的使用Core Foundation类型的对象和Objective-C类型的对象。详细的内容可参考。以下是官方文档中给出的一些例子:

这个时候就必须要要考虑一个问题了,在做Core Foundation与Objective-C类型转换的时候,用哪一种规则来管理对象的内存。显然,对于同一个对象,我们不能够同时用两种规则来管理,所以这里就必须要确定一件事情:哪些对象用Objective-C(也就是ARC)的规则,哪些对象用Core Foundation的规则(也就是MRC)的规则。或者说要确定对象类型转换了之后,内存管理的ownership的改变。

于是苹果在引入ARC之后对Toll-Free Bridging的操作也加入了对应的方法与修饰符,用来指明用哪种规则管理内存,或者说是内存管理权的归属。

这些方法和修饰符分别是:

只是声明类型转变,但是不做内存管理规则的转变。

表示将指针类型转变的同时,将内存管理的责任由原来的Objective-C交给Core Foundation来处理,也就是,将ARC转变为MRC。

比如,还是上面那个例子

我们在第二行做了转化,这时内存管理规则由ARC变为了MRC,我们需要手动的来管理s2的内存,而对于s1,我们即使将其置为nil,也不能释放内存。

等同的,我们的程序也可以写成:

这里我们将result的管理责任交给了ARC来处理,我们就不需要再显式地将CFRelease()了。

对了,这里你可能会注意到一个细节,和ARC中那个4个主要的修饰符(__strong,__weak,...)不同,这里修饰符的位置是放在类型前面的,虽然官方文档中没有说明,但看官方的头文件可以知道。小伙伴们,记得别把位置写错哦:)

呼~ 好了,以上就是本篇文章的主要内容。这次采用了新的排版,感觉比以前有条理得多,希望的大家看的舒服。

文章中如果有任何错误或者问题,可以在下面留言或者给我发信,期待你们的回复。

原创文章,转载请注明出处,谢谢:)

你看不见吗?对哦,你是用手机上的

这是什么来的,是开始蹬入就有啊,还是玩着玩着就突然弹出来的。

我登陆大区后,一直没有反映,然后两分钟后就弹出来这个。昨天还玩的好好的,今天一上就这样。重装了,还是一样。没用。是连游戏都登不上 - -

很有可能是中病毒了,去杀一下毒试一下。

别提了,今天上午360全盘。QQ管家,360能杀的都杀了。就是不行- -

啊,那你的电脑麻烦了。还是拿去专业的去看看吧,不行的话,就一建复原吧。

我要回帖

更多关于 哪位高人来帮我看看 的文章

 

随机推荐