有前面3个文章就够了。
总结下:
1 简单理解:block对应实例化一个结构体,里面成员有block里用到的变量,准备了数据;调用block时,执行对应函数,使用这些数据;2 简单理解:拷贝进来时,没有__block修饰的直接字节拷贝进来,有__block修饰的,为了引地址进来,又定义一个结构体包了一层;
3 block拷贝时,栈到堆上真拷贝,堆到堆上只是引用计数;
4 block拷贝时,block使用的变量同样拷贝,拷贝的原则和上面说的有无__block修饰时的两种情况分别一致;
5 block里使用外部OC对象时,本身就相当于一个赋值拷贝,ARC下就会给对象加引用次数,所以才有了循环引用的事;
6 ARC下,等号赋值,retain、strong、copy都会触发block拷贝到堆上;非ARC有些不一样;
7 ARC下,assign不会把栈上block拷贝到堆上,retain、strong、copy都会;非ARC有些不一样;
8 __block修饰的变量被拷贝到堆上后,__forwarding指向的包装结构体都是堆上那个,这样无论操作栈上还是堆上的包装结构体,实际改变值都会是堆上那个里的;
9 一些有block参数的系统API都有说明,当把栈上block作为参数给这些API时会不会拷贝block,一般都会,所以才没问题;
自测试代码:
#import <Foundation/Foundation.h>
struct TS
{
int a;
int b;
};
@interface TObj : NSObject
@property (nonatomic, assign) void (^bAssign)(void);
@property (nonatomic, retain) void (^bRetain)(void);
@property (nonatomic, copy) void (^bCopy)(void);
@property (nonatomic, strong) void (^bStrong)(void);
@end
@implementation TObj
@end
void Test1(dispatch_block_t block)
{
TObj* obj = [[TObj alloc] init];
obj.bAssign = block;
obj.bRetain = block;
obj.bStrong = block;
obj.bCopy = block;
void (^b)(void) = [block copy];
b();
}
int main(int argc, char * argv[]) {
@autoreleasepool {
__block int val = 10;
int val2 = 11;
__block struct TS tt = {2,3};
void (^block)(void) = ^{
//NSLog(@"%d", val);
int t = val;
int t2 = val2;
struct TS tt1 = tt;
tt1.a = 1;
const struct TS* tt2 = &tt;
};
block();
Test1(^{
int tt = val2;
NSLog(@"xx");
});
int kk = 1;
__block int kk2 = 2;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"after");
int kkt = kk;
kk2 = 3;
block();
});
NSLog(@"ggg");
}
}
clang -rewrite-objc main.m处理后:
struct TS
{
int a;
int b;
};
#ifndef _REWRITER_typedef_TObj
#define _REWRITER_typedef_TObj
typedef struct objc_object TObj;
typedef struct {} _objc_exc_TObj;
#endif
extern "C" unsigned long OBJC_IVAR_$_TObj$_bAssign;
extern "C" unsigned long OBJC_IVAR_$_TObj$_bRetain;
extern "C" unsigned long OBJC_IVAR_$_TObj$_bCopy;
extern "C" unsigned long OBJC_IVAR_$_TObj$_bStrong;
struct TObj_IMPL {
struct NSObject_IMPL NSObject_IVARS;
void (*_bAssign)();
void (*_bRetain)();
void (*_bCopy)();
void (*_bStrong)();
};
// @property (nonatomic, assign) void (^bAssign)(void);
// @property (nonatomic, retain) void (^bRetain)(void);
// @property (nonatomic, copy) void (^bCopy)(void);
// @property (nonatomic, strong) void (^bStrong)(void);
/* @end */
// @implementation TObj
static void(* _I_TObj_bAssign(TObj * self, SEL _cmd) )(){ return (*(void (**)())((char *)self + OBJC_IVAR_$_TObj$_bAssign)); }
static void _I_TObj_setBAssign_(TObj * self, SEL _cmd, void (*bAssign)()) { (*(void (**)())((char *)self + OBJC_IVAR_$_TObj$_bAssign)) = bAssign; }
static void(* _I_TObj_bRetain(TObj * self, SEL _cmd) )(){ return (*(void (**)())((char *)self + OBJC_IVAR_$_TObj$_bRetain)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_TObj_setBRetain_(TObj * self, SEL _cmd, void (*bRetain)()) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TObj, _bRetain), (id)bRetain, 0, 0); }
static void(* _I_TObj_bCopy(TObj * self, SEL _cmd) )(){ return (*(void (**)())((char *)self + OBJC_IVAR_$_TObj$_bCopy)); }
static void _I_TObj_setBCopy_(TObj * self, SEL _cmd, void (*bCopy)()) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct TObj, _bCopy), (id)bCopy, 0, 1); }
static void(* _I_TObj_bStrong(TObj * self, SEL _cmd) )(){ return (*(void (**)())((char *)self + OBJC_IVAR_$_TObj$_bStrong)); }
static void _I_TObj_setBStrong_(TObj * self, SEL _cmd, void (*bStrong)()) { (*(void (**)())((char *)self + OBJC_IVAR_$_TObj$_bStrong)) = bStrong; }
// @end
void Test1(dispatch_block_t block)
{
TObj* obj = ((TObj *(*)(id, SEL))(void *)objc_msgSend)((id)((TObj *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("TObj"), sel_registerName("alloc")), sel_registerName("init"));
((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)obj, sel_registerName("setBAssign:"), (dispatch_block_t)block);
((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)obj, sel_registerName("setBRetain:"), (dispatch_block_t)block);
((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)obj, sel_registerName("setBStrong:"), (dispatch_block_t)block);
((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)obj, sel_registerName("setBCopy:"), (dispatch_block_t)block);
void (*b)(void) = (void (*)())((id (*)(id, SEL))(void *)objc_msgSend)((id)block, sel_registerName("copy"));
((void (*)(__block_impl *))((__block_impl *)b)->FuncPtr)((__block_impl *)b);
}
struct __Block_byref_val_0 {
void *__isa;
__Block_byref_val_0 *__forwarding;
int __flags;
int __size;
int val;
};
struct __Block_byref_tt_1 {
void *__isa;
__Block_byref_tt_1 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
struct TS tt;
};
struct __Block_byref_kk2_2 {
void *__isa;
__Block_byref_kk2_2 *__forwarding;
int __flags;
int __size;
int kk2;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int val2;
__Block_byref_val_0 *val; // by ref
__Block_byref_tt_1 *tt; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val2, __Block_byref_val_0 *_val, __Block_byref_tt_1 *_tt, int flags=0) : val2(_val2), val(_val->__forwarding), tt(_tt->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_val_0 *val = __cself->val; // bound by ref
__Block_byref_tt_1 *tt = __cself->tt; // bound by ref
int val2 = __cself->val2; // bound by copy
int t = (val->__forwarding->val);
int t2 = val2;
struct TS tt1 = (tt->__forwarding->tt);
tt1.a = 1;
const struct TS* tt2 = &(tt->__forwarding->tt);
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->val, (void*)src->val, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->tt, (void*)src->tt, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->val, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->tt, 8/*BLOCK_FIELD_IS_BYREF*/);}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
struct __main_block_impl_1 {
struct __block_impl impl;
struct __main_block_desc_1* Desc;
int val2;
__main_block_impl_1(void *fp, struct __main_block_desc_1 *desc, int _val2, int flags=0) : val2(_val2) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_1(struct __main_block_impl_1 *__cself) {
int val2 = __cself->val2; // bound by copy
int tt = val2;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_z7_wmggyz657wq78njrjhbdjmyh0000gn_T_main_2abab7_mi_0);
}
static struct __main_block_desc_1 {
size_t reserved;
size_t Block_size;
} __main_block_desc_1_DATA = { 0, sizeof(struct __main_block_impl_1)};
struct __main_block_impl_2 {
struct __block_impl impl;
struct __main_block_desc_2* Desc;
int kk;
struct __block_impl *block;
__Block_byref_kk2_2 *kk2; // by ref
__main_block_impl_2(void *fp, struct __main_block_desc_2 *desc, int _kk, void *_block, __Block_byref_kk2_2 *_kk2, int flags=0) : kk(_kk), block((struct __block_impl *)_block), kk2(_kk2->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_2(struct __main_block_impl_2 *__cself) {
__Block_byref_kk2_2 *kk2 = __cself->kk2; // bound by ref
int kk = __cself->kk; // bound by copy
void (*block)() = (void (*)())__cself->block; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_z7_wmggyz657wq78njrjhbdjmyh0000gn_T_main_2abab7_mi_1);
int kkt = kk;
(kk2->__forwarding->kk2) = 3;
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
static void __main_block_copy_2(struct __main_block_impl_2*dst, struct __main_block_impl_2*src) {_Block_object_assign((void*)&dst->kk2, (void*)src->kk2, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->block, (void*)src->block, 7/*BLOCK_FIELD_IS_BLOCK*/);}
static void __main_block_dispose_2(struct __main_block_impl_2*src) {_Block_object_dispose((void*)src->kk2, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->block, 7/*BLOCK_FIELD_IS_BLOCK*/);}
static struct __main_block_desc_2 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_2*, struct __main_block_impl_2*);
void (*dispose)(struct __main_block_impl_2*);
} __main_block_desc_2_DATA = { 0, sizeof(struct __main_block_impl_2), __main_block_copy_2, __main_block_dispose_2};
int main(int argc, char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
__attribute__((__blocks__(byref))) __Block_byref_val_0 val = {(void*)0,(__Block_byref_val_0 *)&val, 0, sizeof(__Block_byref_val_0), 10};
int val2 = 11;
__attribute__((__blocks__(byref))) __Block_byref_tt_1 tt = {(void*)0,(__Block_byref_tt_1 *)&tt, 33554432, sizeof(__Block_byref_tt_1), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, {2,3}};
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, val2, (__Block_byref_val_0 *)&val, (__Block_byref_tt_1 *)&tt, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
Test1(((void (*)())&__main_block_impl_1((void *)__main_block_func_1, &__main_block_desc_1_DATA, val2)));
CFRunLoopGetCurrent();
int kk = 1;
__attribute__((__blocks__(byref))) __Block_byref_kk2_2 kk2 = {(void*)0,(__Block_byref_kk2_2 *)&kk2, 0, sizeof(__Block_byref_kk2_2), 2};
dispatch_after(dispatch_time((0ull), (int64_t)(1 * 1000000000ull)), dispatch_get_main_queue(), ((void (*)())&__main_block_impl_2((void *)__main_block_func_2, &__main_block_desc_2_DATA, kk, (void *)block, (__Block_byref_kk2_2 *)&kk2, 570425344)));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_z7_wmggyz657wq78njrjhbdjmyh0000gn_T_main_2abab7_mi_2);
}
}
自测试代码2:
#import "ViewController.h"
@interface ViewController ()
@end
void Test1(dispatch_block_t block)
{
int k = 1;
block();
dispatch_async(dispatch_get_main_queue(), ^{
int g = k;
block();
NSLog(@"xxx2");
});
}
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
int kk = 1;
__block int kk2 = 2;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"after");
int kkt = kk;
kk2 = 3;
NSLog(@"xxx");
});
NSLog(@"ggg");
void (^block)(void) = ^{
int tt = kk;
NSLog(@"block");
};
dispatch_async(dispatch_get_main_queue(), ^{
kk2 = 4;
block();
NSLog(@"xxx2");
});
Test1(^{
int tt2 = kk;
NSLog(@"ok");
});
NSLog(@"xx");
}
@end