roby的iOS开发文章收集BLOCK探究iOS学习笔记

Block内部实现原理探究

2017-02-23  本文已影响277人  9fda4b908fad

导论

block在我们日常开发过程中经常见到,UIView动画你可以见到,视图跳转你可以看到,多线程你也可以看到,但是似乎我们有的时候只会使用,对于其内部实现并没有那么清楚,接下来就让我们一起看看block内部到底做了些什么.由于本人才疏学浅,如有不对的地方,欢迎大家及时指正

在本篇你能了解到

开始进入今天的正式话题

一. block内部实现的原理

让我看下一下一段代码:

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        int a = 10;
        
        void (^block)() = ^{
            
            NSLog(@"%d",a);
        };
        
        block();
    }
    return 0;
}

so easy是不是,接下来我们把他转化成正在执行时的c/c++代码,将oc代码转化成c/c++代码的命令是:clang -rewrite-objc 文件名
打开终端,cd到你要转化的文件的路径下,执行clang -rewrite-objc 文件名,此时你应该会得到一个cpp文件,这就是我们要的转换后的代码了,恩,打开它

cpp line number
我一点都不觉得他so easy,哈哈

不用紧张,我们不需要一行一行去看它,关键代码下面我已经贴出来了:

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int a;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv__355hmw905bf0w6tmj8t8drr0000gn_T_main_35dd2d_mi_0,a);
        }

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 a = 10;

        void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}
到这我们可以了解到的几点是:

二 . __block到底做了什么

以同样的方法转化成c++代码:我的源代码是这样的

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        __block int a = 10;
        
        void (^block)() = ^{
            
            a = 20;
            
            NSLog(@"%d",a);
        };
        
        block();
    }
    return 0;
}

这是转化后的代码:

struct __Block_byref_a_0 {
  void *__isa;
__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;
  __Block_byref_a_0 *a; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__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_a_0 *a = __cself->a; // bound by ref


            (a->__forwarding->a) = 20;

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_qv__355hmw905bf0w6tmj8t8drr0000gn_T_main_2f1fbb_mi_0,(a->__forwarding->a));
        }
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 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};
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        __attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};

        void (*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));

        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}

同样我们一步一步来看:

最后,希望大家都能理解block更具体的一点东西,如果有不理解,请在下方留言,我会尽力解答的,或者文章有不对的,请多指正,我会及时修改,如果大家有兴趣,后续有时间的话,我再更新一下block循环引用部分,周末愉快.

上一篇 下一篇

猜你喜欢

热点阅读