block

block本质上也是一个OC对象,它内部也有个isa指针,block是封装了函数调用以及函数调用环境的OC对象

Block 分类
NSGlobalBlock
NSMallocBlock
NSStackBlock

GlobalBlock
.位于全局区
.在Block内部不使用外部变量,或者只是用静态变量和全局变量

MallocBlock
.位于堆区
.在Block内部使用局部变量或者OC属性,并且赋值给强引用或者copy修饰符的变量

StackBlock
.位于栈区
.与MallocBlock一样,可以在内部使用局部变量或者OC属性,但是不能赋值给强引用或者copy修饰符的变量

Block拷⻉到堆block
.手动copy
.Block作为返回值
.被强引用or Copy修饰
.系统API包含usingblock

Block flag标识

2002.png

block变量捕获 捕获到内部
局部变量 auto 是 值传递
static 是 指针传递
全局变量 否 直接访问

__block修饰符
__block可以用于解决block内部无法修改auto变量值的问题
__block不能修饰全局变量、静态变量(static)
编译器会将__block变量包装成一个对象

// KC注释: flag 标识
// Values for Block_layout->flags to describe block objects
enum {
    BLOCK_DEALLOCATING =      (0x0001),  // runtime
    BLOCK_REFCOUNT_MASK =     (0xfffe),  // runtime
    BLOCK_NEEDS_FREE =        (1 << 24), // runtime
    BLOCK_HAS_COPY_DISPOSE =  (1 << 25), // compiler
    BLOCK_HAS_CTOR =          (1 << 26), // compiler: helpers have C++ code
    BLOCK_IS_GC =             (1 << 27), // runtime
    BLOCK_IS_GLOBAL =         (1 << 28), // compiler
    BLOCK_USE_STRET =         (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
    BLOCK_HAS_SIGNATURE  =    (1 << 30), // compiler
    BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31)  // compiler
};


struct __main_block_impl_0 {
   struct __block_impl impl;
   struct __main_block_desc_0 *Desc;
  int age;
};
struct __block_impl{
     void *isa;
     int Flags;
     int Reserved;
    void *FuncPtr;
};
struct __main_block_desc_0{
   size_t reserved;
   size_t Block_size;
};

// KC注释: __Block 修饰的结构体
struct Block_byref {
    void *isa;
    struct Block_byref *forwarding;
    volatile int32_t flags; // contains ref count
    uint32_t size;
};

// KC注释: __Block 修饰的结构体 byref_keep 和 byref_destroy 函数 - 来处理里面持有对象的保持和销毁
struct Block_byref_2 {
    // requires BLOCK_BYREF_HAS_COPY_DISPOSE
    BlockByrefKeepFunction byref_keep;
    BlockByrefDestroyFunction byref_destroy;
};

struct Block_byref_3 {
    // requires BLOCK_BYREF_LAYOUT_EXTENDED
    const char *layout;
};


// Copy, or bump refcount, of a block.  If really copying, call the copy helper if present.
// KC重点提示: 这里是核心重点 block的拷贝操作: 栈Block -> 堆Block

void *_Block_copy(const void *arg) {
    struct Block_layout *aBlock;

    if (!arg) return NULL;
    
    // The following would be better done as a switch statement
    aBlock = (struct Block_layout *)arg;
    if (aBlock->flags & BLOCK_NEEDS_FREE) {
        // latches on high
        latching_incr_int(&aBlock->flags);
        return aBlock;
    }
    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
        return aBlock;
    }
    else {
        // Its a stack block.  Make a copy. -> heap
        struct Block_layout *result =
            (struct Block_layout *)malloc(aBlock->descriptor->size);
        if (!result) return NULL;
        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
#if __has_feature(ptrauth_calls)
        // Resign the invoke pointer as it uses address authentication.
        result->invoke = aBlock->invoke;
#endif
        // reset refcount -- 对象 isa 联合体位于
        result->flags &= ~(BLOCK_REFCOUNT_MASK|BLOCK_DEALLOCATING);    // XXX not needed
        result->flags |= BLOCK_NEEDS_FREE | 2;  // logical refcount 1
        _Block_call_copy_helper(result, aBlock);
        // Set isa last so memory analysis tools see a fully-initialized object.
        result->isa = _NSConcreteMallocBlock;
        return result;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容