iOS block低维展开

0x00 示例代码

新建一个 Command Line 项目
main.m 文件代码如下:

#import <Foundation/Foundation.h>

typedef void(^MyBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 17;
        MyBlock block = ^{
            NSLog(@"age = %d", age);
        };
        age = 18;
        block();
    }
    return 0;
}

输出当然是:
age = 17


0x01 低维展开

打开终端,进入main.m文件所在文件夹
输入命令:
xcrun -sdk iphoneos clang -arch arm64 -w -rewrite-objc main.m
会得到一个文件:main.cpp
打开文件,使用快捷键:command + 方向下键
足足有33835行!


main函数被展开成这样:

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

typedef void(*MyBlock)(void);

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int 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) {
  int age = __cself->age; // bound by copy
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_tp_mwb8pcp17p72nqrynqllp1s80000gn_T_main_49d6a6_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 = 17;
        MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));
        age = 18;
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}

block 创建时
MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));

age值传递

所以,外部修改age
不会影响block里面的age


0x02 加入 __block

#import <Foundation/Foundation.h>

typedef void(^MyBlock)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        __block int age = 17;
        MyBlock block = ^{
            NSLog(@"age = %d", age);
        };
        age = 18;
        block();
    }
    return 0;
}

age前面加上__block


0x03 再次展开

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

typedef void(*MyBlock)(void);

struct __Block_byref_age_0 {
 void *__isa;
 __Block_byref_age_0 *__forwarding;
 int __flags;
 int __size;
 int age;
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_age_0 *age; // by ref
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__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_age_0 *age = __cself->age; // bound by ref
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_tp_mwb8pcp17p72nqrynqllp1s80000gn_T_main_26f1f5_mi_0, (age->__forwarding->age));
}
        
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
  _Block_object_assign((void*)&dst->age, (void*)src->age, 8/*BLOCK_FIELD_IS_BYREF*/);
}

static void __main_block_dispose_0(struct __main_block_impl_0*src) {
  _Block_object_dispose((void*)src->age, 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_age_0 age = {(void*)0,(__Block_byref_age_0 *)&age, 0, sizeof(__Block_byref_age_0), 17};
        MyBlock block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_age_0 *)&age, 570425344));
        (age.__forwarding->age) = 18;
        ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
    }
    return 0;
}

此时,多了一个__Block_byref_age_0结构体
__block修饰的变量
展开成了一个__Block_byref_X_Y结构体
X 是 变量名
Y 是 第几个

age 变量,变成了,__Block_byref_age_0结构体
block 在创建时
传入的是这个结构体的引用

而且在函数__main_block_func_0里面
编译器也给了注释:bound by ref
__Block_byref_age_0 *age = __cself->age; // bound by ref

在未加入__block之前
是这样的:bound by copy
int age = __cself->age; // bound by copy

所以,这次能修改成功了


键盘管理,So easy~

https://github.com/xjh093/JHKeyboard


猜你喜欢

转载自blog.csdn.net/xjh093/article/details/108444573