iOS之__block、__strong和__weak使用

一、__weak与__block修饰符到底有什么区别

API Reference对__block变量修饰符有如下几处解释:

<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">//A powerful feature <span class="hljs-operator" style="box-sizing: border-box;">of</span> blocks is that they can modify 
variables <span class="hljs-operator" style="box-sizing: border-box;">in</span> <span class="hljs-operator" style="box-sizing: border-box;">the</span> same lexical scope. You signal that <span class="hljs-operator" style="box-sizing: border-box;">a</span> block 
can modify <span class="hljs-operator" style="box-sizing: border-box;">a</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">variable</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> <span class="hljs-operator" style="box-sizing: border-box;">the</span> __block storage type 
modifier. 
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">
//At function level are __block variables. These are mutable</span>
 <span class="hljs-operator" style="box-sizing: border-box;">within</span> <span class="hljs-operator" style="box-sizing: border-box;">the</span> block (<span class="hljs-operator" style="box-sizing: border-box;">and</span> <span class="hljs-operator" style="box-sizing: border-box;">the</span> enclosing scope) <span class="hljs-operator" style="box-sizing: border-box;">and</span> are preserved
 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">any</span> referencing block is copied <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">to</span> <span class="hljs-operator" style="box-sizing: border-box;">the</span> heap.</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

大概意思归结出来就是: 
__block对象在block中是可以被修改、重新赋值的。

API Reference对__weak变量修饰符有如下几处解释:

<code class="hljs applescript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">__weak specifies <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">a reference</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">that</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">does</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">not</span> keep <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">the</span> 
referenced object alive. A weak <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">reference</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">set</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> nil when
there are no strong references <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">to</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">the</span> object.</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

使用了__weak修饰符的对象,作用等同于定义为weak的property。自然不会导致循环引用问题,因为苹果文档已经说的很清楚,当原对象没有任何强引用的时候,弱引用指针也会被设置为nil。

因此,__block和__weak修饰符的区别其实是挺明显的: 
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。 
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。 
3.__block对象可以在block中被重新赋值,__weak不可以。 
4.__block对象在ARC下可能会导致循环引用,非ARC下会避免循环引用,__weak只在ARC下使用,可以避免循环引用。

PS:__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。

二、block 中使用__weak 和__strong修饰符的问题

问题阐述

在ARC环境下,我们常常会使用weak 的修饰符来修饰一个变量,防止其在block中被循环引用,但是有些特殊情况下,我们在block中又使用strong 来修饰这个在block外刚刚用__weak修饰的变量,为什么会有这样奇怪的写法呢?

后来上网查资料,给的解释就是下面的这段话:
    在block中调用self会引起循环引用,但是在block中需要对weakSelf进行
strong,保证代码在执行到block中,self不会被释放,当block执行完后,
会自动释放该strongSelf;
对于程序员来说,文字说明要有,编码就更少不了了;下面是我对上面的话转译成的代码;

第一步:我们自定义一个类,在该类dealloc方法中加一行打印语句;

@interface SampleObject :NSObject

@end

@implementation SampleObject

- (void)dealloc{

NSLog(@"dealloc %@",[self class]); 

}

@end

第二步:实例化该类,并在block中调用它;(没有加strong修饰符,三秒后释放该对象)

SampleObject* sample = [[SampleObject alloc]init];

self->sample= sample;

__weakSampleObject* weaksample = self->sample;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

NSIntegercount =0;

//__strong SampleObject* strongsample = weaksample;

while(count<10) {

count++;

NSLog(@"aaa %@",weaksample);

sleep(1);

}

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

self->sample=nil;

});

打印结果如下(没有用strong修饰符的打印结果如下):




结论是:如果仅仅使用__weak去修饰变量,当别处把变量释放后,block中该变量也会被释放掉

那么好,我们在把第二步中的方法修改一下,加上strong修饰符:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

__strongSampleObject* strongsample = weaksample;

NSIntegercount =0;

while(count<10) {

count++;

NSLog(@"aaa %@",strongsample);

sleep(1);

}

});

打印结果如下:


结论是当加上修饰符strong时,当别处把变量释放掉,但调用该变量的block如果仍然没有执行结束,那么系统就会等待block执行完成后再释放,对该变量在block中的使用起到了保护作用。当block执行结束后会自动释放掉。


三、为什么系统的block,AFN网络请求的block内使用self不会造成循环引用?

其实只要抓住循环引用的本质,就不难理解。所谓循环引用,是因为当前控制器在引用着block,而block又引用着self即当前控制器,这样就造成了循环引用。系统的block或者AFN等block的调用并不在当前控制器中调用,那么这个self就不代表当前控制器,那自然也就没有循环引用的问题。以上引用均指强引用。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值