Block

2017-04-06  本文已影响11人  6灰太狼9

block是带有局部变量的匿名函数,差不多跟C语言中的函数指针类似,可以当做参数传来传去,而且可以没有名字。同时也是oc对象类型,所以可以吧Block赋值给一个变量,也可以存储在NSArray NSDictionary这样的容器中。

一.Block捕获外部变量实质#

oc中的变量有一下几种

自动变量在block中改变报错

下图的执行结果为block外 i = 101,j = 201,m = 301,n = 401 block内 i = 100,j = 202,m = 302,n = 402为什么先打印外在打印内,这个就不用说了吧!

03975684-C188-44F7-A758-E2F8A75F34DA.png
我们可以看到自动变量i在block中获取的值还是原始的值。而其他变量的却已经增加了!

那么这里就有两个问题
1.为什么block中的自动变量不加__block不容许修改。
2.为什么自动变量的值没有增加,而其他几个变量的值是增加的?
自动变量是以值传递方式传递到Block的构造函数里面去的。Block只捕获Block中会用到的变量。由于只捕获了自动变量的值,并非内存地址,所以Block内部不能改变自动变量的值。 对自定变量来说,Block内部和外部的变量实际上是两种不同的存在:前者是Block内部结构体的一个成员变量,后者是在栈区里的临时变量。 总结一下在Block中改变变量值有2种方式,一是传递内存地址指针到Block中(自动变量nsmutablestring,nsmutablearray 就可以把内存地址指针传到block中),二是改变存储区方式(__block)。

对于对象来说,
在MRC环境下,__block根本不会对指针所指向的对象执行copy操作,而只是把指针进行的复制。
而在ARC环境下,对于声明为__block的外部对象,在block内部会进行retain,以至于在block环境内能安全的引用外部对象。

二.block的分类#

oc中block一般分为_NSConcreteStackBlock,_NSConcreteMallocBlock,_NSConcreteGlobalBlock三种。

  1. _NSStackBlock 存储在栈上
  2. _NSGlobalBlock 存储在全局数据区域(和全局变量一样)
  3. _NSMallocBlock 存储在堆上
    没有引用自动变量或者在全局作用域的Block为_NSGlobalBlock,其他常见的基本上都是_NSMallocBlock ,因为ARC下,block 类型通过=进行传递时,会导致调用objc_retainBlock->_Block_copy->_Block_copy_internal方法链。并导致 NSStackBlock 类型的 block 转换为 NSMallocBlock 类型。

三.block中循环引用的解决和原理#

self.myBlock = ^{
        self.name = @"aa";
}; 存在循环引用   self持有block   在block又对self就行了retain,持有了self

解决方法

__weak __typeof(self) weakself = self;
self.myBlock = ^{
        weakself.name = @"aa";
 };这样就可以block对self的引用变成了弱引用。

这样循环问题是解决了,但是又会导致一个新的问题,假如在block有一个耗时操作,在这个过程self被销毁了,而weakself也会随着self的销毁而销毁,block又要对weakself进行某些操作,这是拿到的weakself就是nil了。
解决方法

__weak __typeof(self) weakself = self;
self.myBlock = ^{
        __strong __typeof(self) strongself = weakself;
        strongself = @"aa";
 };执行bock时,即使self被销毁,我们还有self的一份拷贝(我自己的理解)

strongSelf的目的是因为一旦进入block执行,假设不允许self在这个执行过程中释放,就需要加入strongSelf。block执行完后这个strongSelf 会自动释放,没有不会存在循环引用问题。如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

那么__weak ,__strong (所有权修饰)的原理是什么
在ARC环境下,id类型和对象类型和C语言其他类型不同,类型前必须加上所有权的修饰符。
所有权修饰符总共有4种:
1.__strong修饰符
2.__weak修饰符(如果__weak引用的原对象如果被释放了,那么对应的__weak对象就会被指为nil。)
3.__unsafe_unretained修饰符
4.__autoreleasing修饰符
一般我们如果不写,默认的修饰符是__strong。

上一篇下一篇

猜你喜欢

热点阅读