block的类型
block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型
- __NSGlobalBlock__ (_NSConcreteGlobalBlock )
- __NSStackBlock__ (_NSConcreteStackBlock )
- __NSMallocBlock__ (_NSConcreteMallocBlock )
应用程序内存分配 |
---|
程序区域 .text区 |
数据区域 .data区 |
堆区 |
栈区 |

生成不同类型的block
block类型 | 环境 |
---|---|
NSGlobalBlock(数据区) | 没有访问auto变量 |
NSStackBlock(栈区) | 访问了auto变量 |
NSMallocBlock(堆区) | NSStackBlock调用了copy |
每一种类型的block调用copy后的结果如下所示:
block类型 | 副本源的配置存储域 | 复制效果 |
---|---|---|
NSGlobalBlock(数据区) | 栈区 | 从栈复制到堆区 |
NSStackBlock(栈区) | 程序的数据区 | 什么也不做 |
NSMallocBlock(堆区) | 堆区 | 引用计数增加 |
block的copy
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况
- block作为函数返回值时
- 将block赋值给__strong指针时
- block作为Cocoa API中方法名含有usingBlock的方法参数时
- block作为GCD API的方法参数时
MRC下block属性的建议写法
@property (copy, nonatomic) void (^block)(void);`
ARC下block属性的建议写法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
对象类型的auto变量
当block内部访问了对象类型的auto变量时
-
如果block是在栈上,将不会对auto变量产生强引用
-
如果block被拷贝到堆上
- 如果block被拷贝到堆上
- copy函数内部会调用_Block_object_assign函数
- _Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
函数 | 点用时机 |
---|---|
__main_block_copy_0 | 栈上的block复制到堆时 |
__main_block_dispose_0 | 堆上的block被废弃时 |
//block被拷贝到堆上时调用
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
//会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
_Block_object_assign((void*)&dst->obj,
(void*)src->obj,
8/*BLOCK_FIELD_IS_BYREF*/);
}
//block从堆上移除时调用
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
//会自动释放引用的auto变量(release)
_Block_object_dispose((void*)src->obj,
8/*BLOCK_FIELD_IS_BYREF*/);
}
__weak修饰符
__weak修饰符可以是block生成的结构体中捕获的变量为__weak变量..则可以对变量进行弱引用,解决循环引用问题
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
//捕获__weak变量
NSString __weak *name;
.
.
.
};
在使用clang转换OC为C++代码时,可能会遇到以下问题
cannot create __weak reference in file using manual reference
解决方案:支持ARC、指定运行时系统版本,比如
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
__block修饰符
__block
可以用于解决block内部无法修改auto变量值的问题.但是__block
不能修饰全局变量、静态变量(static)
编译器会将__block变量包装成一个对象
__block int age = 13;
^{
NSLog(@"%d", age);
}();
会生成一下C++代码:
struct __main_block_impl_1 {
struct __block_impl impl;
struct __main_block_desc_1* Desc;
__Block_byref_age_2 *age; // by ref
__main_block_impl_1(void *fp, struct __main_block_desc_1 *desc, __Block_byref_age_2 *_age, int flags=0) : age(_age->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __Block_byref_age_2 {
void *__isa;
__Block_byref_age_2 *__forwarding;
int __flags;
int __size;
int age;
};
网友评论