如果在 Block 内部使用外部的变量,Block 会持有这个变量。下面来看几中特殊的情况,看 Block 对变量的持有情况如何。

typeof

@interface X : NSObject

@property (nonatomic, copy) void(^testBlock1)(void);
@property (nonatomic, copy) void(^testBlock2)(void);
@property (nonatomic, copy) NSString *str; @end @implementation X - (void)test {
self.testBlock1 = ^{
typeof (self) x;
};
} @end

上面代码中, test 方法里面设置了 Block,并且 Block 里面有一句 typeof (self) x,那么在这种情况下,Block 会持有 self 吗?

使用 clang -rewrite-objc 命令,查看 c++ 代码,代码如下:

struct __X__test_block_impl_0 { // Block实现,没有持有 self
struct __block_impl impl;
struct __X__test_block_desc_0* Desc;
__X__test_block_impl_0(void *fp, struct __X__test_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __X__test_block_func_0(struct __X__test_block_impl_0 *__cself) { // Block方法实现 X * x; // typeof (self) x;
}

从代码可以看到,typeof (self) x 被替换成了 X *x,因此这种情况下 Block 不会持有 self。

sizeof

将 test 方法修改如下:

- (void)test {
self.testBlock1 = ^{
size_t i = sizeof (self);
};
}

在上面的方法中,Block 内部有使用 sizeof (self),那么 Block 会持有 self 吗?

同样查看 c++ 代码,代码如下:

struct __X__test_block_impl_0 { // Block实现
struct __block_impl impl;
struct __X__test_block_desc_0* Desc;
X *self; // 持有了 self
__X__test_block_impl_0(void *fp, struct __X__test_block_desc_0 *desc, X *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __X__test_block_func_0(struct __X__test_block_impl_0 *__cself) { // Block方法
X *self = __cself->self; // bound by copy size_t i = sizeof (self);
}

可以看到,在使用 sizeof 时,Block 是持有了 self的。

是否会持有属性

将 test 方法修改如下:

- (void)test {
self.testBlock1 = ^{
self.str = @"KK"; // 设置属性
};
} @end

上面代码中,Block 除了会持有 self,还会持有属性 str 吗?

查看 c++ 代码,代码如下:

struct __X__test_block_impl_0 { // Block实现
struct __block_impl impl;
struct __X__test_block_desc_0* Desc;
X *self; // 只持有了self,未持有属性str
__X__test_block_impl_0(void *fp, struct __X__test_block_desc_0 *desc, X *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __X__test_block_func_0(struct __X__test_block_impl_0 *__cself) { // Block方法实现
X *self = __cself->self; // bound by copy ((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)self, sel_registerName("setStr:"), (NSString *)&__NSConstantStringImpl__var_folders_p6_jy49zvqx2656qb8rbq64hc_w0000gn_T_variable_a3a045_mi_0); // 调用设置属性方法
}

可以看到,Block 没有持有属性 str。

是否会持有实例变量

将 test 方法修改如下:

- (void)test {
self.testBlock1 = ^{
_str = @"KK"; // 调用实例变量
};
}

此时,Block 会持有实例变量吗?

查看 c++ 代码,代码如下:

struct __X__test_block_impl_0 { // Block实现
struct __block_impl impl;
struct __X__test_block_desc_0* Desc;
X *self; // 只持有self,未持有实例变量
__X__test_block_impl_0(void *fp, struct __X__test_block_desc_0 *desc, X *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __X__test_block_func_0(struct __X__test_block_impl_0 *__cself) { // Block方法实现
X *self = __cself->self; // bound by copy (*(NSString **)((char *)self + OBJC_IVAR_$_X$_str)) = (NSString *)&__NSConstantStringImpl__var_folders_p6_jy49zvqx2656qb8rbq64hc_w0000gn_T_variable_d40340_mi_0; // 使用偏移设置实例变量
}

可以看到,Block 没有持有实例变量。

嵌套Block

将 test 方法修改如下:

- (void)test {
int i = 1;
self.testBlock1 = ^{
self.testBlock2 = ^{ // 嵌套Block
self.str = @"KK";
int j = i;
};
};
}

上面代码中使用了嵌套 Block,内层Block使用了变量 i,而外层 Block 没有使用变量 i,外层 Block 是否会持有变量 i 呢?

查看 c++ 代码,代码如下:

struct __X__test_block_impl_0 { // 内层Block实现
struct __block_impl impl;
struct __X__test_block_desc_0* Desc;
X *self; // 持有了self
int i; // 持有了变量i
__X__test_block_impl_0(void *fp, struct __X__test_block_desc_0 *desc, X *_self, int _i, int flags=0) : self(_self), i(_i) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __X__test_block_func_0(struct __X__test_block_impl_0 *__cself) { // 内层Block 方法实现
X *self = __cself->self; // bound by copy
int i = __cself->i; // bound by copy ((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)self, sel_registerName("setStr:"), (NSString *)&__NSConstantStringImpl__var_folders_p6_jy49zvqx2656qb8rbq64hc_w0000gn_T_variable_926b0d_mi_0);
int j = i;
} struct __X__test_block_impl_1 { // 外层Block实现
struct __block_impl impl;
struct __X__test_block_desc_1* Desc;
X *self; // 持有了self
__X__test_block_impl_1(void *fp, struct __X__test_block_desc_1 *desc, X *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __X__test_block_func_1(struct __X__test_block_impl_1 *__cself) { // 外层Block方法实现
X *self = __cself->self; // bound by copy ((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)self, sel_registerName("setTestBlock2:"), ((void (*)())&__X__test_block_impl_0((void *)__X__test_block_func_0, &__X__test_block_desc_0_DATA, self, i, 570425344)));
}

从代码上看,内层 Block 持有 self 和变量 i,外层 Block 只是持有了 self,并未持有变量 i。

Block对变量的引用的更多相关文章

  1. 环境变量、block、修饰符:block对环境变量的引用和修改需要通过修饰符来限定

    环境变量.block.修饰符:block对环境变量的引用和修改需要通过修饰符来限定. http://www.cnblogs.com/fengmin/p/5816580.html - (NSUInteg ...

  2. Block内的强引用

    众所周知,当某个对象持有着一个Block的时候,如果在Block内部使用强引用反过来持有这个对象,就会导致引用循环.为了避免引用循环,可以使用__weak修饰符,苹果的官方文档在用代码演示__weak ...

  3. ARC下的block导致的循环引用问题解析

    ARC下的block导致的循环引用问题解析 更详细细节请参考 http://blog.sina.com.cn/s/blog_8c87ba3b0101m599.html ARC下,copy到堆上的blo ...

  4. 避免Block中的强引用环

    [避免Block中的强引用环] In manual reference counting mode, __block id x; has the effect of not retaining x. ...

  5. Makefile笔记之一 ------ 变量的引用及赋值

    1.变量的引用方式: "$(变量名)"或者"¥{变量名}" 例如: ${Objs}就是取变量Objs的值 注意: 当变量名为单字符是可以采用:"$a& ...

  6. GNU make使用变量⑤变量的引用、定义等

    在 Makefile 中,变量是一个名字(像是 C 语言中的宏),代表一个文本字符串(变量的值).在 Makefile 的目标.依赖.命令中引用变量的地方,变量会被它的值所取代(与 C 语言中宏引用的 ...

  7. Python中的变量、引用、拷贝和作用域

    在Python中,变量是没有类型的,这和以往看到的大部分编辑语言都不一样.在使用变量的时候,不需要提前声明,只需要给这个变量赋值即可.但是,当用变量的时候,必须要给这个变量赋值:如果只写一个变量,而没 ...

  8. 深入理解PHP原理之变量分离/引用

    19 Sep 08 深入理解PHP原理之变量分离/引用(Variables Separation) 作者: Laruence(   ) 本文地址: http://www.laruence.com/20 ...

  9. c++变量的引用---5

    原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/ 1.引用变量的主要用途: 用作函数的形参,通过将引用变量用作参数,函数将使用原始数据而不是其拷贝. 2. ...

随机推荐

  1. 带你十天轻松搞定 Go 微服务之大结局(分布式事务)

    序言 我们通过一个系列文章跟大家详细展示一个 go-zero 微服务示例,整个系列分十篇文章,目录结构如下: 环境搭建 服务拆分 用户服务 产品服务 订单服务 支付服务 RPC 服务 Auth 验证 ...

  2. ASP.NET Core 6框架揭秘实例演示[04]:自定义依赖注入框架

    ASP.NET Core框架建立在一个依赖注入框架之上,已注入的方式消费服务已经成为了ASP.NET Core基本的编程模式.为了使读者能够更好地理解原生的注入框架框架,我按照类似的设计创建了一个简易 ...

  3. Solution -「CF 848D」Shake It!

    \(\mathcal{Description}\)   Link.   初始有一个有向图 \(G=(V,E)\),\(V=\{s,t\}\),\(E=\langle s,t\rangle\),一次操作 ...

  4. netty系列之:可以自动通知执行结果的Future,有见过吗?

    目录 简介 JDK异步缘起 netty中的Executor Future的困境和netty的实现 总结 简介 在我的心中,JDK有两个经典版本,第一个就是现在大部分公司都在使用的JDK8,这个版本引入 ...

  5. XXE外部实体注入漏洞总结

    XXE 漏洞原理 XXE是xml外部实体注入漏洞,应用程序解析xml输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取,命令执行,内网端口扫描攻击内网网站等危害. 漏洞危害 ...

  6. Python+selenium自动循环发邮件

    Python源代码如下: # coding=utf-8 from selenium import webdriver from time import sleep from random import ...

  7. 免费开源Blazor在线Ico转换工具

    行文目录 功能效果演示 实现说明 2.1 其他图片上传 2.2 核心代码:其他图片转Ico 2.3 转换后的Ico文件下载 总结 1. 功能效果演示 仓库地址:IcoTool 在线演示地址:https ...

  8. unittest测试框架,HTMLTestReportCN模块生成的测试报告中展示用例说明的配置方法

    1.前言 想要生成的html测试报告中展示每个测试用例的说明信息,方便了解测试案例的测试点或者其他信息,目前知道的有2种 2.方法介绍 * 方法1: 要添加说明的测试用例,将说明信息用3个引号包裹起来 ...

  9. 传输层 lcx实现本地端口映射&&内网代理

    如果目标服务器由于防火墙的限制,部分端口(例如3389)的数据无法通过防火墙,可以将目标服务器相应端口的数据透传到防火墙允许的端口(例如53),在目标主机上执行如下命令,就可以直接从远程桌面连接目标主 ...

  10. 我哭了 看到RCNN 和FAST RCNN时 想着为什么要选候选框呢?能不能直接回归出来候选框?

    这是不是一个超级好的IDEA 我是不是要发顶会了!!! 看到yolo  直接绝望 果然 你能想到的都已经被发表了. 生不逢时啊!!!