没有参数没有返回值的block
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
void (^myBlock)(void) = ^{
NSLog(@"Hello, World!");
};
myBlock();
}
return 0;
}
clang后的代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m
- 代码为
struct __main_block_impl_0 {
// 因为impl是结构体的一个变量,所以这个impl的地址和结构体的地址一样
struct __block_impl impl;
struct __main_block_desc_0* Desc;
// 构造函数,最后一个参数是带有默认值的
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
//封装了block执行逻辑的函数
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_4h_vk7vdxt51k1c4mbrt28057j80000gn_T_main_73f599_mi_0);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
//定义block的变量
// 给block的 结构体的impl的 funcptr和Desc进行 赋值
void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
// 执行block内部的代码
// 调用block中的funcptr函数,并把block对象一起当参数传入
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
block值的捕获
int age = 10;
void (^myBlock)(void) = ^{
// 值的捕获
NSLog(@"age is %d",age);
};
age = 20;
myBlock();
- clang后的代码
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
// block内部多个age变量,和使用外面的变量名一样
int age;
//age(_age),这个语法的意思是把参数_age赋值给变量age
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
// 从block对象中取出age值
int age = __cself->age; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_4h_vk7vdxt51k1c4mbrt28057j80000gn_T_main_c5a332_mi_0,age);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
int age = 10;
// 这里把age的值传给block的结构体,值传递
void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));
age = 20;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
block捕获局部变量,自动变量是值传递,静态变量是指针传递
// auto:自动变量,离开作用域就销毁,因为创建的变量都有个auto(默认就是auto),这个是c语言的,局部变量分为三种,一种为auto,static,register
// auto int age = 10;
int age = 10;
static int height = 10;
register int regic = 40;
void (^myBlock)(void) = ^{
// 值的捕获
NSLog(@"age is %d, height is %d, regic is %d",age,height,regic);
};
age = 20;
height = 20;
regic = 50;
myBlock();
- clang后的代码
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age;
//保存的是指针(内存地址)
int *height;
int regic;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int *_height, int _regic, int flags=0) : age(_age), height(_height), regic(_regic) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int age = __cself->age; // bound by copy
int *height = __cself->height; // bound by copy
int regic = __cself->regic; // bound by copy
// *height表示的是去height这个内存地址里面所存储的数据
NSLog((NSString *)&__NSConstantStringImpl__var_folders_4h_vk7vdxt51k1c4mbrt28057j80000gn_T_main_d3b457_mi_0,age,(*height),regic);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
// 自动变量(auto),可能随时会被销毁
int age = 10;
// 静态变量,一直在内存中存在
static int height = 10;
// 考虑使用寄存器存储
register int regic = 40;
//静态变量修饰的height被传入的参数是指针(一个内存地址)
void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age, &height, regic));
age = 20;
height = 20;
regic = 50;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
block不会捕获全局变量,直接访问
#import <Foundation/Foundation.h>
int age = 10;
static int height = 10;
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
void (^myBlock)(void) = ^{
// 全局变量
NSLog(@"age is %d, height is %d",age,height);
};
age = 20;
height = 20;
myBlock();
}
return 0;
}
- clang后的代码
int age = 10;
static int height = 10;
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_4h_vk7vdxt51k1c4mbrt28057j80000gn_T_main_8555c3_mi_0,age,height);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
age = 20;
height = 20;
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
block对self捕获,因为self是局部变量,每个方法都会默认有self和_cmd这两个局部参数
@implementation JGPerson
-(instancetype)initWithName:(NSString *)name{
if (self = [super init]) {
self.name = name;
}
return self;
}
-(void)test{
void (^myBlock)(void) = ^{
NSLog(@"%p",self);
};
myBlock();
}
@end
- clang编译后
static instancetype _Nonnull _I_JGPerson_initWithName_(JGPerson * self, SEL _cmd, NSString * _Nonnull name) {
if (self = ((JGPerson *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("JGPerson"))}, sel_registerName("init"))) {
((void (*)(id, SEL, NSString * _Nonnull))(void *)objc_msgSend)((id)self, sel_registerName("setName:"), (NSString * _Nonnull)name);
}
return self;
}
struct __JGPerson__test_block_impl_0 {
struct __block_impl impl;
struct __JGPerson__test_block_desc_0* Desc;
// 捕获了 self
JGPerson *self;
__JGPerson__test_block_impl_0(void *fp, struct __JGPerson__test_block_desc_0 *desc, JGPerson *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __JGPerson__test_block_func_0(struct __JGPerson__test_block_impl_0 *__cself) {
JGPerson *self = __cself->self; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_4h_vk7vdxt51k1c4mbrt28057j80000gn_T_JGPerson_17b7a8_mi_0,self);
}
static void __JGPerson__test_block_copy_0(struct __JGPerson__test_block_impl_0*dst, struct __JGPerson__test_block_impl_0*src) {_Block_object_assign((void*)&dst->self, (void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __JGPerson__test_block_dispose_0(struct __JGPerson__test_block_impl_0*src) {_Block_object_dispose((void*)src->self, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __JGPerson__test_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __JGPerson__test_block_impl_0*, struct __JGPerson__test_block_impl_0*);
void (*dispose)(struct __JGPerson__test_block_impl_0*);
} __JGPerson__test_block_desc_0_DATA = { 0, sizeof(struct __JGPerson__test_block_impl_0), __JGPerson__test_block_copy_0, __JGPerson__test_block_dispose_0};
//test方法,可以 看到self和_cmd都是局部参数
static void _I_JGPerson_test(JGPerson * self, SEL _cmd) {
void (*myBlock)(void) = ((void (*)())&__JGPerson__test_block_impl_0((void *)__JGPerson__test_block_func_0, &__JGPerson__test_block_desc_0_DATA, self, 570425344));
((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);
}
static NSString * _Nonnull _I_JGPerson_name(JGPerson * self, SEL _cmd) { return (*(NSString * _Nonnull *)((char *)self + OBJC_IVAR_$_JGPerson$_name)); }
static void _I_JGPerson_setName_(JGPerson * self, SEL _cmd, NSString * _Nonnull name) { (*(NSString * _Nonnull *)((char *)self + OBJC_IVAR_$_JGPerson$_name)) = name; }
总结
- block本质是一个oc对象,它的内部有个isa指针
- block是 封装了函数调用以及函数调用环境的oc对象
- block的底层结构如下: block的结构
block捕获的情况
block捕获情况block的类型
block的类型注意如果是在mrc情况下,访问了auto变量的block是在栈空间的,也就是stackblock,这样会被栈自动释放,如果要使用,就得使用copy,从栈拷贝到堆空间中,不能让他自动释放掉,不在使用时候得releas掉,再arc使用时候,访问auto变量,就是mallocblock了
在使用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
对象类型的auto变量
- 当block内部访问了对象类型的auto变量时
- 如果block在栈上,将不会对auto变量产生强引用
- 如果block被copy到堆上
- 会调用 block内部的copy函数,copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会根据auto变量的修饰符(__weak,__strong,__unsafe_unretained)做出相应的操作,形成强引用或弱引用
- 如果block从堆上移除
- 会调用block内部的dispose函数
-
dispose函数内部会调用_Block_object_dispose函数,这个函数会自动释放引用的auto变量,类似release操作,引用计数器-1
copy函数和dispose函数调用时机
使用__block来修饰变量
#import <Foundation/Foundation.h>
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __Block_byref_a_0 {
void *__isa;
struct __Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
struct __Block_byref_a_0 *a; // by ref
};
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
__block int a = 10;
void (^myBlock)(void) = ^ {
a = 20;
};
// myBlock();
struct __main_block_impl_0 *blockImpl = (__bridge struct __main_block_impl_0 *)myBlock;
NSLog(@"%@",&a);
}
return 0;
}
使用__block会把变量,包装成一个对象(一个结构体里面有isa指针),block持有这个结构体,对这个结构体进行内存管理
网友评论