block实现源码分析4-总结和自测试

有前面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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值