iOS block以及变量捕获

这篇具有很好参考价值的文章主要介绍了iOS block以及变量捕获。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Block是什么

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

扩展:

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

void (^block)(void) = ^{
        NSLog(@"Hello");
    };
    
    NSLog(@"%@", [block class]);
    NSLog(@"%@", [[block class] superclass]);
    NSLog(@"%@", [[[block class] superclass] superclass]);
    NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);
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

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编译后的底层代码

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、静态局部变量

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;
}

编译后的结果:

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

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;
}

编译后:

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博客文章来源地址https://www.toymoban.com/news/detail-797313.html

到了这里,关于iOS block以及变量捕获的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • iOS Block介绍

    目的就是能够直接存储一个代码块的实现部分,而不需要再去定义一个函数。void (^myblock)() = 可以直接跟实现的代码块,就是将函数整体拿过来,把函数名去掉,在前面加一个block标识^。这样在别的代码块中也可以直接调用这个部分,这就是oc的优化之处。 其实block就是去相当

    2024年02月14日
    浏览(31)
  • iOS——Block循环引用

    Capturing ‘self’ strongly in this block is likely to lead to a retain cycle 典型的循环引用 self 持有了 block block 持有了 self (self.name) 这样就形成了 self - block - self 的循环引用 强弱共舞 使用 中介者模式 __weak typeof(self) weakSelf = self 将循环引用改为 weakself - self - block - weakself 表面看上去还是一

    2024年02月14日
    浏览(26)
  • iOS-Block

    Blocks的学习 Block根据其类型可以分为三类: 全局Block( NSGlobalBlock ) 栈Block( NSMallocBlock ) 堆Block( NSStackBlock ) 而其区分的规则为: 如果没有引用局部变量,或者只引用了静态变量和全局变量,则为全局Block,如果内部有使用局部变量,如果有被强指针引用过,就是堆Blo

    2024年02月16日
    浏览(34)
  • iOS——Block two

    Block  的实质究竟是什么呢?类型?变量?还是什么黑科技?  Blocks 是  带有局部变量的匿名函数 在项目中添加 blocks.m 文件,并写好 block 的相关代码。 打开「终端」,执行  cd XXX/XXX  命令,其中  XXX/XXX  为 block.m 所在的目录。 继续执行 clang -rewrite-objc block.m 执行完命令之

    2024年02月14日
    浏览(26)
  • iOS——【Blocks】

    Blocks是C语言的扩充功能,即带有自动变量的匿名函数。匿名函数就是不带函数名的函数。这一概念同样被称为“闭包”,lambda计算等。 自动变量是在函数内部声明的变量,其作用域仅限于声明它的函数内部。这意味着它们只能在其声明的函数内部使用,并且在函数执行完毕

    2024年03月18日
    浏览(36)
  • iOS——Block签名

    首先来看block结构体对象 Block_layout (等同于clang编译出来的 __Block_byref_a_0 ) 其中 Block_layout 是基础的block结构空间,而部分block则拥有 Block_descriptor_2 和 Block_descriptor_3 结构,其中的 flags 标识记录了一些信息 第1位:释放标记,一般常用BLOCK_NEEDS_FREE做位与操作,一同传入flags,

    2024年02月14日
    浏览(41)
  • iOS系统崩溃的捕获

    相信大家在开发iOS程序的时候肯定写过各种Bug,而其中最为严重的Bug就是会导致崩溃的Bug(一般来说妥妥的P1级)。在应用软件大大小小的各种异常中,崩溃确实是最让人难以接受的行为。毕竟崩溃意味着用户将丢失应用程序运行中的所有上下文环境,丢失其所有未保存的数

    2024年04月13日
    浏览(42)
  • Java NIO(Java Non-Blocking IO:非阻塞式IO)(2)

    1.NIO非阻塞网络编程相关的(Selector、SelectionKey、ServerScoketChannel和SocketChannel)关系梳理图: 说明: ①.当客户端连接时,会通过服务器端ServerSocketChannel得到/生成对应的SocketChannel; ②.通过register(Selector sel,int ops)方法将SocketChannel注册到Selector上(一个Selector上可以注册多个SocketChannel); ③

    2024年02月02日
    浏览(46)
  • 学习笔记——SPARTAN 6 系列IO资源学习笔记

    学习笔记——SPARTAN 6 系列IO资源学习笔记 参考:《Spartan-6 FPGA SelectIO Resources》User Guide 所有Spartan-6 fpga都具有可配置的高性能SelectIO驱动器和接收器,支持各种标准接口。每个IOB都包含输入、输出和3态SelectIO驱动程序。这些驱动程序可以配置为各种I/O标准。 •单端I/O标准(LVC

    2024年02月03日
    浏览(67)
  • ios客户端学习笔记(七):iOS客户端的UI设计

    iOS客户端的UI设计是指在iOS操作系统上开发应用程序时所涉及的用户界面设计,包括应用程序的布局、颜色、字体、图标等元素的设计。良好的UI设计应该能够提高用户体验,使用户能够轻松地使用应用程序。 在iOS客户端的UI设计中,需要考虑以下几个方面: 应用程序布局应

    2023年04月26日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包