Block对变量的引用
如果在 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对变量的引用的更多相关文章
- 环境变量、block、修饰符:block对环境变量的引用和修改需要通过修饰符来限定
环境变量.block.修饰符:block对环境变量的引用和修改需要通过修饰符来限定. http://www.cnblogs.com/fengmin/p/5816580.html - (NSUInteg ...
- Block内的强引用
众所周知,当某个对象持有着一个Block的时候,如果在Block内部使用强引用反过来持有这个对象,就会导致引用循环.为了避免引用循环,可以使用__weak修饰符,苹果的官方文档在用代码演示__weak ...
- ARC下的block导致的循环引用问题解析
ARC下的block导致的循环引用问题解析 更详细细节请参考 http://blog.sina.com.cn/s/blog_8c87ba3b0101m599.html ARC下,copy到堆上的blo ...
- 避免Block中的强引用环
[避免Block中的强引用环] In manual reference counting mode, __block id x; has the effect of not retaining x. ...
- Makefile笔记之一 ------ 变量的引用及赋值
1.变量的引用方式: "$(变量名)"或者"¥{变量名}" 例如: ${Objs}就是取变量Objs的值 注意: 当变量名为单字符是可以采用:"$a& ...
- GNU make使用变量⑤变量的引用、定义等
在 Makefile 中,变量是一个名字(像是 C 语言中的宏),代表一个文本字符串(变量的值).在 Makefile 的目标.依赖.命令中引用变量的地方,变量会被它的值所取代(与 C 语言中宏引用的 ...
- Python中的变量、引用、拷贝和作用域
在Python中,变量是没有类型的,这和以往看到的大部分编辑语言都不一样.在使用变量的时候,不需要提前声明,只需要给这个变量赋值即可.但是,当用变量的时候,必须要给这个变量赋值:如果只写一个变量,而没 ...
- 深入理解PHP原理之变量分离/引用
19 Sep 08 深入理解PHP原理之变量分离/引用(Variables Separation) 作者: Laruence( ) 本文地址: http://www.laruence.com/20 ...
- c++变量的引用---5
原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/ 1.引用变量的主要用途: 用作函数的形参,通过将引用变量用作参数,函数将使用原始数据而不是其拷贝. 2. ...
随机推荐
- java创建自定义类的对象数组
1 public class Student{ 2 static int number = 0; // 静态变量的访问可以不用创建类的实例就可就可使用< 类名.属性 >的方法访问 3 ...
- python unittest控制用例的执行顺序
为什么要进行顺序控制呢?使用过testng的同学就知道,它相对于junit来说有更强大的功能,其中的一个功能就是依赖测试.什么是依赖测试呢?简单的说一下就是,A方法运行时,其中有个变量的取值是B方法的 ...
- java多线程编程(一)
一.概念基础 进程:正在进行中的程序(直译). 线程:就是进程中一个负责程序执行的控制单元(执行路径) 一个进程中可以多执行路径,称之为多线程. 一个进程中至少要有一个线程. 开启多个线程是为了同时运 ...
- 键盘弹起及lab时的动态计算高度 --董鑫
1.键盘抬起或掉下时,动态计算高度 2.动态计算Label的高度 计算的高度时,numberOfLines必须设置为0: 2.1 ios7.0之后 2.2 iOS 7.0之前
- python——平时遇到问题记录
# pyhs2安装 #centos yum install groupinstall 'development tools' yum install python34-devel yum instal ...
- 赠送4本《 PHP 程序员面试笔试宝典》
< PHP 程序员面试笔试宝典>历时一年,由机械工业出版社出版,在 2018 年 11 月问世.全书共八个章节,涉及 面试笔试经验技巧.PHP 基础知识.PHP 进阶知识,PHP 面向对象 ...
- 【Azure 应用服务】部署Jar到App Service for Linux,因启动命令路径配置错误而引起:( Application Error 问题
问题描述 App Service for Linux 资源创建完成后,通过FTP方式把 .jar包(logdemo.jar)包上传到 /site/wwwroot/ 文件夹后,在App Service的 ...
- 深入MySQL(三):MySQL的索引的应用
在MySQL的优化中,索引的作用绝对算是一个大头,很多时候索引使用得当可以使得一个查询的效率提高几个数量级,同时它还具有自动排序等功能.所以如果是深入MySQL,那么索引绝对是其中重要的一部分. My ...
- 【一天一个小知识10/20】Unity安卓获取麦克风并录音保存。
2021-10-20 10:42:16 #region 模块信息 // **************************************************************** ...
- 从.net开发做到云原生运维(零)——序
1. 为什么要写这个系列的文章 大家看到标题的时候肯定会感觉到困惑,这个标题里的两件事物好像并不是很搭.说到.net开发大家一般都会想到asp.net做网站,或者是wpf和winform这类桌面开发, ...