G*C*D和Block中使用block self循环引用用怎么查看

提示:点击上方&CocoaChina&↑免费订阅我们知道在Block使用中,Block内部能够读取外部局部变量的值。但我们需要改变这个变量的值时,我们需要给它附加上__block修饰符。__block另外一个比较多的使用场景是,为了避免某些情况下Block循环引用的问题,我们也可以给相应对象加上__block 修饰符。为什么不使用__block就不能在Block内部修改外部的局部变量?我们把以下代码通过 clang -rewrite-objc 源代码文件名重写:int main(int argc, const char * argv[]) {
@autoreleasepool {
int val = 10;
void (^block)(void) = ^{
NSLog(@&%d&, val);
return 0;}得到如下代码:struct __main_block_impl_0 {
struct __block_
struct __main_block_desc_0* D
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) {
impl.isa = &_NSConcreteStackB
impl.Flags =
impl.FuncPtr =
}};static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int val = __cself-& // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__val_folders_gm_0jk35cwn1dqym280000gn_T_main_41daf1_mi_0, val);}static struct __main_block_desc_0 {
size_t Block_} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __
int val = 10;
void (*block)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, val);
((void (*)(__block_impl *))((__block_impl *)block)-&FuncPtr)((__block_impl *)block);
return 0;}我们注意到Block实质被转换成了一个__main_block_impl_0的结构体实例,其中__main_block_impl_0结构体的成员包括局部变量val。在__main_block_impl_0结构体的构造方法中,val作为第三个参数传递进入。但执行我们的Block时,通过block找到Block对应的方法执行部分__main_block_func_0,并把当前block作为参数传递到__main_block_func_0方法中。__main_block_func_0的第一个参数声明如下:struct __main_block_impl_0 *__cself它和Objective-C的self相同,不过它是指向 __main_block_impl_0 结构体的指针。这个时候我们就可以通过__cself-&val对该变量进行访问。那么,为什么这个时候不能给val进行赋值呢?因为main函数中的局部变量val和函数__main_block_func_0不在同一个作用域中,调用过程中只是进行了值传递。当然,在上面代码中,我们可以通过指针来实现局部变量的修改。不过这是由于在调用__main_block_func_0时,main函数栈还没展开完成,变量val还在栈中。但是在很多情况下,block是作为参数传递以供后续回调执行的。通常在这些情况下,block被执行时,定义时所在的函数栈已经被展开,局部变量已经不在栈中了(block此时在哪里?),再用指针访问就……所以,对于auto类型的局部变量,不允许block进行修改是合理的。__block 到底是怎么工作的?我们把以下代码通过 clang -rewrite-objc 源代码文件名重写:int main(int argc, const char * argv[]) {
@autoreleasepool {
__block NSInteger val = 0;
void (^block)(void) = ^{
NSLog(@&val = %ld&, val);
return 0;}可得到如下代码:struct __Block_byref_val_0 {
__Block_byref_val_0 *__
NSI};struct __main_block_impl_0 {
struct __block_
struct __main_block_desc_0* D
__Block_byref_val_0 * // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_val_0 *_val, int flags=0) : val(_val-&__forwarding) {
impl.isa = &_NSConcreteStackB
impl.Flags =
impl.FuncPtr =
}};static void __main_block_func_0 (struct __main_block_impl_0 *__cself) {
__Block_byref_val_0 *val = __cself-& // bound by ref
(val-&__forwarding-&val) = 1;}static void __main_block_copy_0 (struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst-&val, (void*)src-&val, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0 (struct __main_block_impl_0*src)
_Block_object_dispose((void*)src-&val, 8/*BLOCK_FIELD_IS_BYREF*/);}static struct __main_block_desc_0 {
size_t Block_
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};int main(int argc, const char * argv[]) {
__AtAutoreleasePool __
__attribute__((__blocks__(byref))) __Block_byref_val_0 val = {(void*)0,(__Block_byref_val_0 *)&val, 0, sizeof(__Block_byref_val_0), 0};
void (*block)(void) = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_val_0 *)&val, );
((void (*)(__block_impl *))((__block_impl *)block)-&FuncPtr)((__block_impl *)block);
NSLog((NSString *)&__NSConstantStringImpl__val_folders_gm_0jk35cwn1dqym280000gn_T_main_d7fc4b_mi_0, (val.__forwarding-&val));
return 0;}我们发现由__block修饰的变量变成了一个__Block_byref_val_0结构体类型的实例。该结构体的声明如下:struct __Block_byref_val_0 {
__Block_byref_val_0 *__
NSI};注意到这个结构体中包含了该实例本身的引用 __forwarding。我们从上述被转化的代码中可以看出 Block 本身也一样被转换成了 __main_block_impl_0 结构体实例,该实例持有__Block_byref_val_0结构体实例的指针。我们再看一下赋值和执行部分代码被转化后的结果:static void __main_block_func_0 (struct __main_block_impl_0 *__cself) {
__Block_byref_val_0 *val = __cself-& // bound by ref
(val-&__forwarding-&val) = 1;}((void (*)(__block_impl *))((__block_impl *)block)-&FuncPtr)((__block_impl *)block);我们从__cself找到__Block_byref_val_0结构体实例,然后通过该实例的__forwarding访问成员变量val。成员变量val是该实例自身持有的变量,指向的是原来的局部变量。如图所示:上面部分我们展示了__block变量在Block查看和修改的过程,那么问题来了:当block作为回调执行时,局部变量val已经出栈了,这个时候代码为什么还能正常工作呢?我们为什么是通过成员变量__forwarding而不是直接去访问结构体中我们需要修改的变量呢? __forwarding被设计出来的原因又是什么呢?存储域通过上面的描述我们知道Block和__block变量实质就是一个相应结构体的实例。我们在上述转换过的代码中可以发现 __main_block_impl_0 结构体构造函数中, isa指向的是 _NSConcreteStackBlock。Block还有另外两个与之相似的类:_NSConcreteStackBlock 保存在栈中的block,出栈时会被销毁_NSConcreteGlobalBlock 全局的静态block,不会访问任何外部变量_NSConcreteMallocBlock 保存在堆中的block,当引用计数为0时会被销毁上述示例代码中,Block是被设为_NSConcreteStackBlock,在栈上生成。当我们把Block作为全局变量使用时,对应生成的Block将被设为_NSConcreteGlobalBlock,如:void (^block)(void) = ^{NSLog(@&This is a Global Block&);};int main(int argc, const char * argv[]) {
@autoreleasepool {
return 0;}该代码转换后的代码中,Block结构体的成员变量isa的初始化如下: impl.isa = &_NSConcreteGlobalB那么_NSConcreteMallocBlock在什么时候被使用呢分配在全局变量上的Block,在变量作用域外也可以通过指针安全的访问。但分配在栈上的Block,如果它所属的变量作用域结束,该Block就被废弃。同样地,__block变量也分配在栈上,当超过该变量的作用域时,该__block变量也会被废弃。这个时候_NSConcreteMallocBlock就登场了,Blocks提供了将Block和__block变量从栈上复制到堆上的方法来解决这个问题。将分配到栈上的Block复制到堆上,这样但栈上的Block超过它原本作用域时,堆上的Block还可以继续存在。复制到堆上的Block,它的结构体成员变量isa将变为:impl.isa = &_NSConcreteMallocB而_block变量中结构体成员__forwarding就在此时保证了从栈上复制到堆上能够正确访问__block变量。在这种情况下,只要栈上的_block变量的成员变量__forwarding指向堆上的实例,我们就能够正确访问。我们一般可以使用copy方法手动将 Block 或者 __block变量从栈复制到堆上。比如我们把Block做为类的属性访问时,我们一般把该属性设为copy。有些情况下我们可以不用手动复制,比如Cocoa框架中使用含有usingBlock方法名的方法时,或者GCD的API中传递Block时。当一个Block被复制到堆上时,与之相关的__block变量也会被复制到堆上,此时堆上的Block持有相应堆上的__block变量。当堆上的__block变量没有持有者时,它才会被废弃。(这里的思考方式和objc引用计数内存管理完全相同。)而在栈上的__block变量被复制到堆上之后,会将成员变量__forwarding的值替换为堆上的__block变量的地址。这个时候我们可以通过以下代码访问:val.__forwarding-&val如下面:__block变量和循环引用问题__block修饰符可以指定任何类型的局部变量,上面的转换代码中,有如下代码:static void __main_block_copy_0 (struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst-&val, (void*)src-&val, 8/*BLOCK_FIELD_IS_BYREF*/);}static void __main_block_dispose_0 (struct __main_block_impl_0*src)
_Block_object_dispose((void*)src-&val, 8/*BLOCK_FIELD_IS_BYREF*/);}当Block从栈复制到堆时,会使用_Block_object_assign函数持有该变量(相当于retain)。当堆上的Block被废弃时,会使用_Block_object_dispose函数释放该变量(相当于release)。由上文描述可知,我们可以使用下述代码解除Block循环引用的问题:__block id tmp =void(^block)(void) = ^{
tmp =};block();通过执行block方法,nil被赋值到_block变量tmp中。这个时候_block变量对 self 的强引用失效,从而避免循环引用的问题。使用__block变量的优点是:通过__block变量可以控制对象的生命周期在不能使用__weak修饰符的环境中,我们可以避免使用__unsafe_unretained修饰符在执行Block时可动态地决定是否将nil或者其它对象赋值给__block变量但是这种方法有一个明显的缺点就是,我们必须去执行Block才能够解除循环引用问题,否则就会出现问题。点击下方“阅读原文”参与iOS开发者大调查,赢取2015年定制台历↓↓↓CocoaChina(cocoachinabbs) 
 文章为作者独立观点,不代表微头条立场
的最新文章
在太空孤独飞行了九年多,美国宇航局的新视野号探测器即将抵达目的地——冥王星。北京时间7月14日19:49,新 提示:点击上方"CocoaChina"↑免费订阅写在前面本文来自iOS Tutorial Team 的在职业生涯早期,我曾期望有人能给我一份职场指南,这样当遇到之前未曾遇到的事情时,我就不会感到如此的孤单和沮丧。多学多快乐码农是战斗族群,怎么可能会被困难吓倒呢?你现在怎么做,代表着你以后怎么活,你的将来,是你现在的选择造就的。▲点击上方“CocoaChina”关注即可免费学习 iOS 开发▲点击上方“CocoaChina”关注即可免费学习 iOS 开发▲点击上方“CocoaChina”关注即可免费学习 iOS 开发从校园到职场千万别贪舒服,多劳收获多,成长也快!回答面试官的问题是有技巧滴~程序员的你还在为职业规划迷茫么?GitHub上排名前10的 Objective-C 项目及其常用方法很重要的一点是,请先思考。英国是全球第六大的游戏消费市场。本文列出Objective-C语言的语法和Java,C++的对比,这样你就会很容易Objective-C的语法是怎么回事了。技术人员本身的技术发展遇到瓶颈,如何突破呢?在今年的 WWDC 大会上,苹果公布了一个为旗下所有 OS 打造的全新文件系统 APFS。希望本文能帮助你在面试的一些常识和基础细节方面做到位,顺利闯入下一关。我认为命名是开发过程中最基本的任务之一。本文重点讨论在Jenkins管理的持续集成以及测试的环境中,我们如何通过引入Docker来优化资源的配置,提高整个环境的性能以及稳定性。作为程序员不仅仅要理解产品的实现细节,我们还要知道产品的动机、定位和防线,知道产品为谁而做、为何而做。在这篇文章中,我将会谈到Objective-C(以及其他语言)中的普遍模式,并且在Swift中找到它的模式。在iOS开发中经常需要使用的或不常用的知识点的总结,几年的收藏和积累(踩过的坑)。前10个APP适合每个人用,后5个APP可能只适合开发者使用了。你可以把这个看做是一个从对计算机丝毫不懂到可以和业界牛人谈笑风生一路披荆斩棘的过来人的一些经验。提供超出客户预期的价值这篇文章会对 IQKeyboardManager 自动解决键盘遮挡问题的方法进行分析。设计师必须让用户在 “首次使用" 就有好的体验!单元测试"和"测试代码"的区别就像钻石和煤炭,虽然都由碳元素(程序代码)构成,但前者价值远远大于后者。遵守代码规范可以提高代码可读性, 降低后期维护成本。一切为了更加干净整洁的代码,“May the clean code be with you”。直观优先, 不要过度封装。在技术面试中一般会从3个方面考核个人能力,项目的开发能力,技术能力的广度和技术能力的深度。一边是需求的猛烈变动,一边是开发成本的居高不下。能否聪明的选择技术栈甚至生死攸关。Talk is cheap, show me the code!目前为止我已经有五个流行项目(登上Github的Trending页),所以想分享我的一些经验和方法。每个初学者貌似都是拿到编程入门就开始撸语法编程技巧等,要知道编程规范性也是一个很重要的点,而且,好的编程规范26岁的程序员,大到身居要职,小到我这种打杂工,出路在哪?在于读书、写博客、工作实践、积累人脉也。如果你的目标是成为一名通用软件工程师,那么未来5-10年需要掌握的技能与过去5-10年并没有什么太多的差别。今天给大家讲一个职场上位的故事今天正好看到了一个网站专门精选推荐写代码时应该听的音乐,叫“Music for Programming”,试听了一些感觉还不错,因此在这里推荐给各位。现在除了 Touch ID 和截屏,我已经不用 Home 键了。Git和GitHub可能提高日常效率的10个常用技巧。美国宇航局即 NASA 将 253 个软件项目开源目前托管在Gitithub上,NASA 希望可以通过开源收在重构的过程中,你的阅读代码的能力、写出优秀代码的能力以及系统架构能力都会稳步提升。区分成功和不成功的团队,并不是看他们产品成功与否,而是看他们能否顺利地连续作战。手指在键盘上飞速跳跃,终端上的代码也随着飞舞,是的这确实很酷。本文整理了git的大纲~iOS有个特性就是应用将其自身”绑定”到一个自定义 URL scheme 上,该 scheme用于从浏览器或其他应用中启动本应用。常见的分享到第三方之间的跳转都是基于Scheme的。cocoachinabbsCocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。热门文章最新文章cocoachinabbsCocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。Block&代码块中用到了self引用问题,导致循环引用
&循环引用指两个对象相互强引用了对方,即retain了对方,从而导致谁也释放不了谁的内存泄露问题。如声明一个delegate时一般用assign而不能用retain或strong,因为你一旦那么做了,很大可能引起循环引用。在以往的项目中,我几次用动态内存检查发现了循环引用导致的内存泄露。
&这里讲的是block的循环引用问题,因为block在拷贝到堆上的时候,会retain其引用的外部变量,那么如果block中如果引用了他的宿主对象,那很有可能引起循环引用,如:
- (void)dealloc
& & NSLog(@"no cycle
- (id)init
& & self = [super
& & if (self) {
#if TestCycleRetainCase1
& //会循环引用
& self.myblock = ^{
& & & [self
doSomething];
#elif TestCycleRetainCase2
& //会循环引用
& __block TestCycleRetain *weakSelf =
& self.myblock = ^{
& & & [weakSelf
doSomething];
#elif TestCycleRetainCase3
& //不会循环引用
& __weak TestCycleRetain *weakSelf =
& self.myblock = ^{
& & & [weakSelf
doSomething];
#elif TestCycleRetainCase4
& //不会循环引用
& __unsafe_unretained TestCycleRetain *weakSelf =
& self.myblock = ^{
& & & [weakSelf
doSomething];
& NSLog(@"myblock is %@", self.myblock);
- (void)doSomething
& & NSLog(@"do
Something");
int main(int argc, char *argv[]) {
& & @autoreleasepool {
& TestCycleRetain* obj = [[TestCycleRetain alloc]
& return 0;
&经过上面的ARC环境测试发现,在加了__weak和__unsafe_unretained的变量引入后,TestCycleRetain方法可以正常执行dealloc方法,而不转换和用__block转换的变量都会引起循环引用。
但是实际情况是:
1)MRC情况下,用__block可以消除循环引用。
2)ARC情况下,必须用弱引用才可以解决循环引用问题,iOS
5之后可以直接使用__weak,之前则只能使用__unsafe_unretained了,__unsafe_unretained缺点是指针释放后自己不会置空。
示例代码:(关于使用block会防止循环引用的代码示例)
1)在ARC下,由于__block抓取的变量一样会被Block retain,所以必须用弱引用才可以解决循环引用问题,iOS
5之后可以直接使用__weak,之前则只能使用__unsafe_unretained了,__unsafe_unretained缺点是指针释放后自己不会置空。示例代码:
//iOS 5之前可以用__unsafe_unretained
//__unsafe_unretained typeof(self) weakSelf =
__weak typeof(self) weakSelf =
self.myBlock = ^(int paramInt)
//使用weakSelf访问self成员
& & [weakSelf
anotherFunc];
2)在非ARC下,显然无法使用弱引用,这里就可以直接使用__block来修饰变量,它不会被Block所retain的,参考代码:
__block typeof(self) weakSelf =
self.myBlock = ^(int paramInt)
//使用weakSelf访问self成员
& & [weakSelf
anotherFunc];
In manual reference counting mode, __ has the
effect of not retaining x. In ARC mode, __ defaults to
retaining x (just like all other values). To get the manual
reference counting mode behavior under ARC, you could use
__unsafe_unretained __. As the name __unsafe_unretained
implies, however, having a non-retained variable is dangerous
(because it can dangle) and is therefore discouraged. Two better
options are to either use __weak (if you don’t need to support iOS
4 or OS X v10.6), or set the __block value to nilto break the
retain cycle.
学习参考好文
1):http://my.oschina.net/u/1432769/blog/390401
2)://block-retain-cycle-problem/
3):/blog/?p=1493
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。  在完成项目期间,不可避免的会使用到block,因为block有着比delegate和notification可读性更高,而且看起来代码也会很简洁。于是在目前的项目中大量的使用block。  之前给大家介绍了一下在开发的过程中使用到了代理以及block,并详细的介绍了一下delegate和block的相似之处。(如有兴趣可以去看我之前的文章 & & & & 链接:&/MasterPeng/p/5210263.html)  主要是因为在开发的时候,有时候由于疏忽大意或者一些其他的原因,导致了使用block时造成了循环引用从而导致了内存泄露。block 循环引用的主要原因:在block中引用了外部变量。  下面为大家举一个简单的例子,像下面这段代码:  brush.getCardInfo=^(NSDictionary&*info){  [self test];  };  像上面这段代码,self其实是一个本地变量而不是block内部变量,如果声明为assign,代码执行到block内部就会出错。  但是这又带来另一个问题,就是self的引用计数+1。这意味着很可能会导致循环引用。self持有brush,brush持有block,block持有self。结果就是内存泄漏。解决方法:  __weak&CurrentViewController *blockSelf&=&&  brush.getCardInfo=^(NSDictionary&*info){  [blockSelf test];  };  通过__weak修饰变量这个方式,告诉block这个变量的引用计数不要+1。从而避免循环引用的问题。声明block的时候都是用copy来修饰  使用copy修饰的原因:  block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。&&  使用retain也可以,但是block的retain行为默认是用copy的行为实现的,因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。关于block更多的应用或者实现,大家可以参考巧神的一篇讲解block的博客 & & &链接://a-look-inside-blocks/
阅读(...) 评论()为什么系统的block,AFN网络请求的block内使用self不会造成循环引用?
像系统UIView动画的block,AFN的block等,我们可以直接在block里写self,而不是weakSelf。而自定义的block如果直接使用了self,或者成员变量的话,都会形成强引用,造成内存泄漏。
按投票排序
关于这个问题,UIView和AFN还是不一样的。首先循环引用发生的条件就是持有这个block的对象,被block里边加入的对象持有。当然是强引用。所以UIView的动画block不会造成循环引用的原因就是,这是个类方法,当前控制器不可能强引用一个类,所以循环无法形成。而AFN无循环是因为绝大部分情况下,你的网络类对象是不会被当前控制器引用的,这时就不会形成引用环。当然我不知道AFN是否做了别的处理,按照这样来说的话,如果你的控制器强引用了这个网络类的对象,而且在block里面引用了当前控制器,也是会发生循环引用的。
其实只要抓住循环引用的本质,就不难理解。所谓循环引用,是因为当前控制器在引用着block,而block又引用着self即当前控制器,这样就造成了循环引用。系统的block或者AFN等block的调用并不在当前控制器中调用,那么这个self就不代表当前控制器,那自然也就没有循环引用的问题。以上引用均指强引用。
因为被释放掉了……
执行完手动释放block,不就不会循环引用了
因为系统的block在结束的时候会释放引用对象,有兴趣可以看,GCD源码。
楼主的问题里面一般是包含了此种写法:在一个VC中@interface ClassA@property (nonatomic,copy)...@implementation ClassA- (void)requestData{
//假设这是一个block吧
requestBlock^(id responseData){
self.data = responseD
}}..VC和block互相持有。而AF里面的流程是这样的:图1图2
不会。原因。af源代码自己看不就明白 么。
系统的block不清楚,来说说AFN。AFN(我看的2.6.3版本)框架中,你传入的block是被AFURLSessionManagerTaskDelegate对象引用。而AFURLSessionManagerTaskDelegate被mutableTaskDelegatesKeyedByTaskIdentifier字典引用,AFN在block执行完后,mutableTaskDelegatesKeyedByTaskIdentifier字典会移除AFURLSessionManagerTaskDelegate对象,这样block也被释放。基本是这个原因,具体的细节自己看AFN源代码去。
我觉得是这个block是在方法中 不属于对象的属性 并没有被对象持有 所以并不会引起循环引用
已有帐号?
无法登录?
社交帐号登录到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf
Objective C 的 Block 是一个很实用的语法,特别是与GCD结合使用,可以很方便地实现并发、异步任务。但是,如果使用不当,Block 也会引起一些循环引用问题(retain cycle)—— Block 会 retain ‘self’,而 ‘self‘ 又 retain 了 Block。因为在 ObjC 中,直接调用一个实例变量,会被编译器处理成 ‘self-&theVar’,’self’ 是一个 strong 类型的变量,引用计数会加 1,于是,self retains queue, queue retains block,block retains self。
解决 retain circle
Apple 官方的建议是,传进 Block 之前,把 ‘self’ 转换成 weak automatic 的变量,这样在 Block 中就不会出现对 self 的强引用。如果在 Block 执行完成之前,self 被释放了,weakSelf 也会变为 nil。
示例代码:
__weak __typeof__(self) weakSelf =
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomething];
clang 的文档表示,在 doSomething 内,weakSelf 不会被释放。但,下面的情况除外:
__weak __typeof__(self) weakSelf =
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomething];
[weakSelf doOtherThing];
在 doSomething 中,weakSelf 不会变成 nil,不过在 doSomething 执行完成,调用第二个方法 doOtherThing 的时候,weakSelf 有可能被释放,于是,strongSelf 就派上用场了:
__weak __typeof__(self) weakSelf =
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong __typeof(self) strongSelf = weakS
[strongSelf doSomething];
[strongSelf doOtherThing];
__strong 确保在 Block 内,strongSelf 不会被释放。
在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。
如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。
原文作者:
原文链接:
版权声明:自由转载-非商用-非衍生-保持署名 |
发表评论:
TA的最新馆藏}

我要回帖

更多关于 block循环引用的原理 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信