iOS打基础之Block二三事

Block概念

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

Block的创建和使用

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

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

@property (nonatomic, copy) dispatch_block_t block;

在这里插入图片描述

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. */
};

分析

  • 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;
}
...
  • 使用__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/

猜你喜欢

转载自blog.csdn.net/Ambrosedream/article/details/126018486