• iOS打基础之Block二三事


    Block概念

    Objective-C中的Block本质是一个对象。 也可以把block理解为闭包。

    Block的创建和使用

    void (^block变量名)(NSString* 参数1...);
    block变量名 = ^(NSString* 参数1...){
    	函数体
    };
    block变量名();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在GCD中给我们提供了一个无返回值,无参数的block定义。

    @property (nonatomic, copy) dispatch_block_t block;
    
    • 1

    在这里插入图片描述

    Block的实现

    struct Block_descriptor {
        unsigned long int reserved;
        unsigned long int size;
        void (*copy)(void *dst, void *src);
        void (*dispose)(void *);
    };
    
    struct Block_layout {
        void *isa;
        int flags;
        int reserved;
        void (*invoke)(void *, ...);
        struct Block_descriptor *descriptor;
        /* Imported variables. */
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    分析

    • isa指针,代表着Block本身也是被当做一个对象进行处理的。
      • 这样设计有什么好处吗?
      • 还可以怎样设计吗?
    • flags 用于按bit位表示一些block附加信息。
      • 怎么使用flags
      • 为什么要设计bits
    • reserved 保留变量
      • 怎样使用保留变量?
    • invoke 函数指针,指向block实现的函数调用地址。
      • 指向的函数是什么样子的?
    • descriptor 表示该block的附加描述信息。
      • size,大学
      • copy 拷贝函数
      • dispose 释放函数
    • variables 捕获的变量

    Block分类

    NSConcreteGlobalBlock

    不捕获变量。

    NSConcreteStackBlock

    分配到占上的实例。

    思考

    • 既然Block是一个对象,为什么会被分配到栈上?为什么要把他分配到栈上?这样设计有什么好处?

    NSConcreteMallocBlock

    堆Block,通常不会在源码中出现。默认当一个block在被copy时,才会将block复制到堆上。

    Block变量捕获

    • 对于Block外变量的引用,block默认将其复制到数据结构中实现访问。
    • 对于__block修饰的外部变量引用,block是将其复制到其引用地址实现访问的。

    __block 原理

    struct __Block_byref_i_0 {
        void *__isa;
        __Block_byref_i_0 *__forwarding;
        int __flags;
        int __size;
        int i;
    };
    
    struct __main_block_impl_0 {
        struct __block_impl impl;
        struct __main_block_desc_0* Desc;
        __Block_byref_i_0 *i; // by ref
        __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_i_0 *_i, int flags=0) : i(_i->__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_i_0 *i = __cself->i; // bound by ref
    
        printf("%d\n", (i->__forwarding->i));
        (i->__forwarding->i) = 1023;
    }
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 使用__block后,捕获的变量以一个__Block_byref_i_0的形式存在,同时在__main_block_func_0中使用的事__Block_byref_i_0的结构体指针,保证改变的是外部的变量的值。
    • __Block_byref_i_0结构体中保存的是捕获的外部变量的地址,forwarding的作用是在拷贝到堆上后,保证指针指向的是堆上的地址。

    Objective-C 中的block

    ARC模式下,将只有全局block堆block

    Block的使用场景

    • GCD 使用block做任务回调。
    • 使用Block进行通信。

    Swift的闭包

    • 待补充…

    参考文章

    [1] https://blog.devtang.com/2013/07/28/a-look-inside-blocks/

  • 相关阅读:
    java毕业生设计高考志愿智能辅助填报系统计算机源码+系统+mysql+调试部署+lw
    idea 连接远程 docker 并部署项目到 docker
    如何用一个简单的内容升级心理学技巧将转化率提高了845%
    动态背景颜色渐变HTML
    【毕业设计】基于大数据的京东消费行为分析与可视化 - python 机器学习
    Echarts 社区分享
    Markdown还能这么玩?这款开源神器绝了
    2023年【陕西省安全员C证】最新解析及陕西省安全员C证试题及解析
    QT:用qt实现一个登录界面
    Sublime下运行javascript,并带彩色提示
  • 原文地址:https://blog.csdn.net/Ambrosedream/article/details/126018486