iOS block以及变量捕获

Block是什么

Block也是一个OC对象,内部也有isa指针。

扩展:

instance对象的isa指向class对象

class对象的isa指向meta-class对象

meta-class对象的isa指向基类的meta-class对象

objectivec 复制代码
void (^block)(void) = ^{
        NSLog(@"Hello");
    };
    
    NSLog(@"%@", [block class]);
    NSLog(@"%@", [[block class] superclass]);
    NSLog(@"%@", [[[block class] superclass] superclass]);
    NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);
objectivec 复制代码
2020-11-09 22:24:30.042560+0800 Interview01-Block的本质[1489:30598] __NSGlobalBlock__
2020-11-09 22:24:30.043005+0800 Interview01-Block的本质[1489:30598] __NSGlobalBlock
2020-11-09 22:24:30.043103+0800 Interview01-Block的本质[1489:30598] NSBlock
2020-11-09 22:24:30.043163+0800 Interview01-Block的本质[1489:30598] NSObject

Block的类型

NSGlobalBlock(_NSConcreteGlobalBlock)(存放在数据区) (不访问auto变量的block 即便是访问了static局部变量 或者全局变量)

NSStackBlock(_NSConcreteStackBlock)(存放在栈区 系统管理内存)(访问了auto变量:auto变量就是局部变量)

NSMallocBlock(_NSConcreteMallocBlock) (存放在堆区 程序员管理内存) (__NSStackBlock__调用了copy)

不同类型变量的捕获方式

1、局部变量和block

使用局部变量的block

objectivec 复制代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 10;
        block = ^{
            // age的值捕获进来(capture)
            NSLog(@"age is %d, ", age);
        };
        age = 20;
        block();
    }
    return 0;              
}

clang编译后的底层代码

objectivec 复制代码
struct __test_block_impl_0 {
  struct __block_impl impl;
  struct __test_block_desc_0* Desc;
  int age;
  __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

可以看到,在block的内部多了成员变量_age,并且在构造这个block时,会把age的值直接传进去,几_age=age,可以看出来这时是block捕获了局部变量,并且进行了值传递。

2、静态局部变量

objectivec 复制代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // auto:自动变量,离开作用域就销毁
        auto int age = 10;
        static int height = 10;

        void (^block)(void) = ^{
            // age的值捕获进来(capture)
            NSLog(@"age is %d, height is %d", age, height); // 10  20
        };

        age = 20;
        height = 20;

        block();

    }
    return 0;
}

编译后的结果:

objectivec 复制代码
struct __test_block_impl_0 {
  struct __block_impl impl;
  struct __test_block_desc_0* Desc;
  int age;
  int *height;
  __test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

//定义的时候
block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age, &height));
//执行的时候
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
  int age = __cself->age; // bound by copy
  int *height = __cself->height; // bound by copy


        NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age, (*height));
    }

可以看出来age传递的是值,但是静态局部变量height传递的是指针。

3、全局变量和block

objectivec 复制代码
int age_ = 10;
static int height_ = 10;
void (^block)(void);
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void (^block)(void) = ^{
            NSLog(@"age is %d, height is %d", age_, height_);
        };

        age_ = 20;
        height_ = 20;

        block();
    }
    return 0;
}

编译后:

objectivec 复制代码
struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  // 构造函数(类似于OC的init方法),返回结构体对象
  __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 __test_block_func_0(struct __test_block_impl_0 *__cself) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age_, height_);
    }

可以看到全局变量没有捕获到block内部,是直接访问的,所以每次访问都能获得最新值。

未完待续

参考文档:

block ios 深入理解 ios __block的作用_imking的技术博客_51CTO博客
iOS OC基础知识笔记_ios oc y-CSDN博客

相关推荐
用户380341658829742 分钟前
YUV→RGB 的颜色范围与矩阵:画面发灰的真凶
ios
深念Y1 小时前
黑苹果P400-直通显示折腾全记录-20260907
macos·ios·系统·黑苹果·苹果·英伟达·p400
2501_915921431 小时前
抓包工具对比:Charles、TraceEagle、Wireshark、Fiddler 与 Proxyman
网络协议·计算机网络·网络安全·ios·adb·https·udp
9765033352 小时前
iOS 上架/审核 4.3a全面解读-最新
flutter·ios·objective-c·uniapp
2501_915106323 小时前
Flutter iOS混淆打包详细教程与步骤
android·flutter·ios·小程序·uni-app·iphone·webview
外域速览7 小时前
OpenAI 智能体「越狱」风波未平,苹果折叠屏 iPhone Ultra 下周三登场
人工智能·ios·iphone
getapi1 天前
1 在 macOS 电脑上更新 Flutter iOS 应用到 App Store
flutter·macos·ios
可乐鸡翅yeah_1 天前
App WebView 加载 M3U8 流媒体踩坑,安卓 iOS 混合开发播放异常定位
android·ios·harmonyos·m3u8·m3u8在线播放
代码的小搬运工2 天前
KVO学习
学习·ios·cocoa
方白羽2 天前
为什么 Android 非要用 Intent 传值?
android·ios·harmonyos