美文网首页架构师之路111
关于Block再啰嗦几句

关于Block再啰嗦几句

作者: OldSix1987 | 来源:发表于2016-05-27 14:07 被阅读134次

1.一共有6种类型:

BLOCK_EXPORT void * _NSConcreteStackBlock[32];

// 只有在调用copy的情况下才会生成MallocBlock,ARC下会默认把栈上的block复制到堆上

BLOCK_EXPORT void * _NSConcreteMallocBlock[32];

BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];

//  后面三种主要是用GC

BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32];

BLOCK_EXPORT void * _NSConcreteAutoBlock[32];

BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32];

2.block是oc对象,含有isa的结构体

3.block只有在主动调用copy的时候, 才可能会对外部变量(主要讲oc对象)的引用计数器造成影响,会对变量进行retain操作,(__block修饰后的变量在MRC下不会对oc对象进行retain操作,需要手动管理内存),其他所有情况都不会对其引用计数器造成改变。

但是这里需要明确的是,block结构体内部其实会const一份外部变量(以参数的形式传入结构体)作为其结构体的成员变量,也就是将变量的副本存到了block结构体,所以对原对象的引用计数器没有影响。

然后在block触发函数指针调用的时候可以直接进行值传递(注意这里不是赋值的意思,是指函数方法内会生成一个局部变量,也就是外部对象,对它进行一个值传递,赋值为结构体内的变量值,也叫做截取捕捉变量),但是修改内容以及复制都不被允许,因为const化了。(全局与静态,以及__block修饰 除外)。

其实道理上也可以理解,外部的变量的作用域与生命周期问题,即使block通过指针拿到该变量的修改复制权限,其实也很危险,但变量作用域到头释放的时候,block内部的指针就是野指针。

但是%p打地址的时候你会发现对象地址还是同一个(因为本质上还是同一个对象,外部release了,Block内部也用不了)。

4.__block修饰变量相当于在block结构体内做了一次指针引用。

针对oc对象,__block其实可以看作一种提醒编译器优化的标识,加上的话该oc对象会在block结构体内会生成一个__block的对象(含有isa的结构体,含有该对象,flag = 131 = BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT,,意思是使用结构体内部的copy/dispose辅助函数手动管理,内部无需再次retain,直接指针赋值即可),并且可以使该__block对象在栈和堆上都可以得到(fowarding指针),所以也就是,即使block从栈复制到堆上,所以加上__block修饰的外部变量,当copy到堆上的时候,外部变量不会被复制(或retain),而是直接赋值指针地址,因此该变量的引用计数器保持不变。

如果不加的话(flag = BLOCK_FIELD_IS_OBJECT ),当copy到堆上时,block会调用了[obj retain]方法,引用计数器会+1, 否则复制到堆上时,会对找不到该变量(因为局部变量受作用域影响,肯定比block的生命周期短),且在复制的过程中,通过fowarding指针可以找到堆上的该变量。

非oc对象复制的话,加__block的话,flag = BLOCK_FIELD_IS_BYREF,即使复制多次也只会复制一次,后面只是将该变量的引用计数器+1(但其实对于基本数据类型的话,我们也不会去关心引用计数器)。不加__block的话,相当于block结构体对基本数据类型对象做了一次const化到了结构体内,只能使用,不能修改和赋值。

5.block作为参数,或者作为返回值时,MRC下,一定要copy到堆上,否则会超出作用域会被释放,导致野指针。这里也是日常代码时常见场合,建议最好使用ARC,编译器会默认把block复制到堆上,也就是[[block copy] autorelease]。

6.block对于以参数形式传进来的对象,不会强引用。因为传进来的参数,根本不会进入block的结构体,只是以形参的方式在block触发函数指针时出现。

7.block的循环引用问题,主要发生在当把block作用成员变量时,切记,如果block内部使用了self,或者其他成员变量(基本数据类型也不行),都会引起循环引用,__weak(ARC)和__block(MRC)都可以解决该问题。

e.g.:

__weak _-typeof(self) weakSelf = self;

^{[weakSelf someMethod];}

对block的理解不深的情况下使用,很容易造成循环引用的泛滥。其实在苹果原生的设计系统中,在View与ViewController间的通讯主要还是使用delegate。

而使用block的场合主要是类方法,比如UIView:

[UIView animateWithDuration:1.0 animations:^{

        // 动画效果

}];

8.全局变量,全部静态变量,静态变量,不需要加入__block也可以在block中被修改,全局的好理解, 作用域、生命周期都比block要大要长,所以在block内可以直接使用、修改。

静态变量(存储在.data区)也是同理,但是方案上,block在结构体内部获取了静态变量的指针,所以可以直接修改。

9.^{printf("Hello World!")} 在MRC下,clang后会发现,没有引入外部变量时,但是block结构体isa指针仍然为StackBlock,但开启ARC后,isa指针我GlobalStack指针。

推荐几篇好文&源码:(源码难看,但是还得看,否则都是道听途说)

1.http://www.jianshu.com/p/e03292674e60#

2.http://www.jianshu.com/p/51d04b7639f1

3.http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/BlocksRuntime/runtime.c

4.http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/BlocksRuntime/Block_private.h

5.http://blog.ibireme.com/2013/11/27/objc-block/

6.http://mobile.51cto.com/hot-403914.htm

7.http://mobile.51cto.com/hot-403931.htm

8.http://mobile.51cto.com/hot-403935.htm

相关文章

  • 关于Block再啰嗦几句

    1.一共有6种类型: BLOCK_EXPORTvoid*_NSConcreteStackBlock[32]; //...

  • 再啰嗦几句

    不要把自已当成神,我们生而为人,是人就有不完美,不完美就意味着我们不能把所有的事情做到完美。 生活中,我们总是想让...

  • 啰嗦几句“啰嗦”

    近来读约翰·洛克的《人类理解论》,结合之前贝莱克的《人类知识原理》,小调谈谈“啰嗦”。这两本书真够啰嗦,一个道理翻...

  • 啰嗦几句

    都说人生不如意十之八九,都说没到终点全都不作数,都说中途如何虐,但求结局美好。好吧,最近情况有点糟,所以想说个皆大...

  • 啰嗦几句

    1.当我们可笑的自以为发现了真理,认识了世界,再回首发现不过是可笑的冲动,自以为是的愚蠢,我不敢说我在“考证历史”...

  • 啰嗦几句

    早上就被叫去一个企业修电脑,这边还没完事,另一个车间又打电话。老主板居然不支持U盘启动,忙活了半天,只得把硬盘拆下...

  • 啰嗦几句

    脑子里一直过着只有吃吃喝喝的日子,所以它什么事都不想,也就愚钝了。自己慢慢变成一个傻子,除了吃喝玩乐,其他事情都有...

  • 啰嗦几句

    从上学到工作,从学习到生活,大部分的我们可以阶段性去努力,去付出,去坚持。这些都可以。连大人都说,等你考上大学了,...

  • 啰嗦几句

    伪装人之所以去伪装,正是害怕面对失去,不知如何处理失去所带来的心碎,也不知如何缝合失去所导致的伤口,所以像一个披着...

  • 啰嗦几句

    大家早上好! 这会儿阳光明媚,却出奇的冷。 昨天还是32℃,今天就降温了。天气预报果然大多数还是准的,昨天早上还说...

网友评论

    本文标题:关于Block再啰嗦几句

    本文链接:https://www.haomeiwen.com/subject/iowjrttx.html