Block_copy
首先,我们需要查看Block.h。这里有以下定义:

#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))

可以看到Block_copy,纯粹是一个宏定义,它将传入的参数强制转换为const void *并将其传递给_Block_copy()。
接下来我们在runtime.cpp中找到了关于_Block_copy的定义。

void *_Block_copy(const void *arg) {
    struct Block_layout *aBlock;
    // 1 如果传递进来的是NULL,那么就直接返回一个NULL
    if (!arg) return NULL;

    // The following would be better done as a switch statement
    // 2 将传递进来的Block强制转换为Block_layout结构
    aBlock = (struct Block_layout *)arg;
    // 3 判断如果是堆Block那么就增加引用计数,然后直接返回Block
    if (aBlock->flags & BLOCK_NEEDS_FREE) {
        // latches on high
        latching_incr_int(&aBlock->flags);
        return aBlock;
    }
    // 4 如果是全局Block,则无需执行任何操作,直接返回这个Block
    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
        return aBlock;
    }
    else {
        // Its a stack block.  Make a copy.
        // 5 如果到了这里,那么必然是栈Block。这种情况下,需要将Block复制到堆中。在第一步中,molloc()用于创建所需大小的内存空间,如果内存分配失败,那么直接返回NULL,否则就继续执行
        struct Block_layout *result =
            (struct Block_layout *)malloc(aBlock->descriptor->size);
        if (!result) return NULL;
        // 6 使用memmove()函数用于将当前堆栈分配的Block逐位复制到刚刚在堆上分配好的内存中。
        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
#if __has_feature(ptrauth_calls)
        // Resign the invoke pointer as it uses address authentication.
        // 7 重新定义调用指针,因为它使用地址身份验证。
        result->invoke = aBlock->invoke;
#endif
        // 8 更新Block的flags,重置引用计数,确保引用计数为0
        // reset refcount
        result->flags &= ~(BLOCK_REFCOUNT_MASK|BLOCK_DEALLOCATING);    // XXX not needed
        result->flags |= BLOCK_NEEDS_FREE | 2;  // logical refcount 1
        // 9 调用Block中的辅助函数(通常是用来拷贝Block中捕获的参数的)
        _Block_call_copy_helper(result, aBlock);
        // Set isa last so memory analysis tools see a fully-initialized object.
        // 10 将Block的isa设置为_NSConcreteMallocBlock
        result->isa = _NSConcreteMallocBlock;
        return result;
    }
}

这个方法的作用

如果传递进来的是NULL,那么就直接返回一个NULL
将传递进来的Block强制转换为Block_layout结构
判断如果是堆Block那么就增加引用计数,然后直接返回Block
如果是全局Block,则无需执行任何操作,直接返回这个Block
如果到了这里,那么必然是栈Block。这种情况下,需要将Block复制到堆中。在第一步中,molloc()用于创建所需大小的内存空间,如果内存分配失败,那么直接返回NULL,否则就继续执行
使用memmove()函数用于将当前堆栈分配的Block逐位复制到刚刚在堆上分配好的内存中。
重新定义调用指针,因为它使用地址身份验证。
更新Block的flags,重置引用计数,确保引用计数为0
调用Block中的辅助函数(通常是用来拷贝Block中捕获的参数的)
将Block的isa设置为_NSConcreteMallocBlock

Block_release
Block_copy对应的另一半是Block_release,实际上是这样一个宏

#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
让我来看一下Block_release的代码

void _Block_release(const void *arg) {
// 1. 将指针转换为Block_layout结构
struct Block_layout *aBlock = (struct Block_layout *)arg;
if (!aBlock) return;
// 2. 如果是全局block,那么直接返回
if (aBlock->flags & BLOCK_IS_GLOBAL) return;
// 3. 如果不是堆block,那么直接返回
if (! (aBlock->flags & BLOCK_NEEDS_FREE)) return;
// 4. 处理堆block的引用计数
if (latching_decr_int_should_deallocate(&aBlock->flags)) {
// 5. 释放block捕获的变量
_Block_call_dispose_helper(aBlock);
_Block_destructInstance(aBlock);
// 6. 释放堆block
free(aBlock);
}
}

ps;iOS开发交流技术群:[欢迎你的加入;[563513413](:https://jq.qq.com/?_wv=1027&k=ZWTkXmx3) ] 

将指针转换为Block_layout结构
如果是全局block,那么直接返回
如果不是堆block,那么直接返回
处理堆block的引用计数
释放block捕获的变量
释放堆block