Skip to content

Commit 598a4a2

Browse files
committed
edit 添加__block的原理介绍【38-在block内如何修改block外部变量?】
1 parent 148d4e0 commit 598a4a2

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

01《招聘一个靠谱的iOS》面试题参考答案/《招聘一个靠谱的iOS》面试题参考答案(下).md

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -654,17 +654,52 @@ autoreleasepool 以一个队列数组的形式实现,主要通过下列三个函
654654
检测代码中是否存在循环引用问题,可使用 Facebook 开源的一个检测工具 [***FBRetainCycleDetector***](https://github.com/facebook/FBRetainCycleDetector) 。
655655
656656
###38. 在block内如何修改block外部变量?
657-
默认情况下,在block中访问的外部变量是复制过去的,即:**写操作不对原变量生效**。但是你可以加上`__block`来让其写操作生效,示例代码如下:
657+
默认情况下,在block中访问的外部变量是复制过去的,即:**写操作不对原变量生效**。但是你可以加上 `__block` 来让其写操作生效,示例代码如下:
658658
659+
660+
```Objective-C
659661
__block int a = 0;
660-
void (^foo)(void) = ^{
662+
void (^foo)(void) = ^{
661663
a = 1;
662-
}
663-
f00();
664+
};
665+
foo();
664666
//这里,a的值被修改为1
667+
```
668+
669+
670+
这是 [微博@唐巧_boy](http://weibo.com/tangqiaoboy)的《iOS开发进阶》中的第11.2.3章节中的描述。你同样可以在面试中这样回答,但你并没有答到“点子上”。真正的原因,并没有书这本书里写的这么“神奇”,而且这种说法也有点牵强。面试官肯定会追问“为什么写操作就生效了?”正真的原因是这样的:
671+
672+
673+
> `__block` 关键字修饰的外部对象,被 block 内部被引用后,该对象的指针地址就会由栈区变成堆区的地址。栈区内容出了作用域就会被销毁,堆区内容则不会。
674+
675+
我们可以打印下内存地址来进行验证:
665676

677+
```Objective-C
678+
__block int a = 0;
679+
NSLog(@"定义前:%p", &a); //栈区
680+
void (^foo)(void) = ^{
681+
a = 1;
682+
NSLog(@"block内部:%p", &a); //堆区
683+
};
684+
NSLog(@"定义后:%p", &a); //堆区
685+
foo();
686+
```
687+
688+
```Objective-C
689+
2016-05-17 02:03:33.559 LeanCloudChatKit-iOS[1505:713679] 定义前:0x16fda86f8
690+
2016-05-17 02:03:33.559 LeanCloudChatKit-iOS[1505:713679] 定义后:0x155b22fc8
691+
2016-05-17 02:03:33.559 LeanCloudChatKit-iOS[1505:713679] block内部: 0x155b22fc8
692+
```
693+
694+
他们三个的内存地址转成10进制就是
695+
696+
1. 定义后前:6171559672
697+
2. block内部:5732708296
698+
3. 定义后后:5732708296
699+
700+
中间相差 418.5M 的空间,又因为iOS中栈区的内存只有1M,Mac也只有8M,显然a已经是在堆区了。
666701

667-
参考链接:[微博@唐巧_boy](http://weibo.com/tangqiaoboy)的著作《iOS开发进阶》中的第11.2.3章节
702+
这也证实了我们的猜测:a 在定义前是栈区,但只要进入了 block 区域,就变成了堆区。这才是 `__block` 关键字的真正作用。
668703

669704
###39. 使用系统的某些block api(如UIView的block版本写动画时),是否也考虑引用循环问题?
670705

0 commit comments

Comments
 (0)