With the exception of retains done as part of initializing a __strong parameter variable or reading a __weak variable, whenever these semantics call for retaining a value of block-pointer type, it has the effect of a Block_copy. The optimizer may remove such copies when it sees that the result is used only as an argument to a call.
在ARC环境下编译器会自动触发
1 2 3
id objc_retainBlock(id x){ return (id)_Block_copy(x); }
// Copy, or bump refcount, of a block. If really copying, call the copy helper if present. void *_Block_copy(constvoid *arg) { structBlock_layout *aBlock; // 判断传入的block是否为空 if (!arg) returnNULL; // The following would be better done as a switch statement aBlock = (struct Block_layout *)arg; if (aBlock->flags & BLOCK_NEEDS_FREE) { // latches on high // 如果这个block是一个要被释放的block,当然这个block肯定是堆block了,既然你都有对象了,咱们也就没有继续谈下去的必要了,return latching_incr_int(&aBlock->flags); return aBlock; } elseif (aBlock->flags & BLOCK_IS_GLOBAL) { // 如果是个全局block,return return aBlock; } else { // Its a stack block. Make a copy. // 如果是个栈block,那我们的故事就开始了 // 首先当然是申请内存啦,之前的block占多大的内存,咱们就得占多大 struct Block_layout *result = malloc(aBlock->descriptor->size); // 申请失败那自然拜拜咯 if (!result) returnNULL; // memmove()将之前栈上所有的数据迁移到刚刚申请的内存上 memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first // reset refcount // 重设引用计数 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. // 最后将isa设置成_NSConcreteMallocBlock result->isa = _NSConcreteMallocBlock; return result; } }