block分類
1. __NSGlobalBlock__
void(^globalBlock)(void) = ^ {
NSLog(@"1111111");
};
NSLog(@"%@",globalBlock);
.......................
<__NSGlobalBlock__: 0x108fb70b8>
聲明一個block腕巡,沒有對外界變量持有為 __NSGlobalBlock__
- 位于全局區(qū)
- 在Block內(nèi)部不使用外部變量胳搞,或者只適用靜態(tài)變量和全局變量会前。
2. __NSMallocBlock__
int a = 10;
void (^ malloBlock)(void) = ^{
NSLog(@"Cooci - %d",a);
};
NSLog(@"%@",malloBlock);
.......................
<__NSMallocBlock__: 0x6000010ec840>
- 位于堆區(qū)
- 在Block內(nèi)部使用局部變量或者OC屬性拨黔,并且賦值給強引用或者Copy修飾蛔溃。
當block對外界變量持有是,就會從__NSStackBlock__
copy成__NSMallocBlock__
篱蝇,具體情況下文分析
3. __NSStackBlock__
int a = 10;
void (^ malloBlock)(void) = ^{
NSLog(@"Cooci - %d",a);
};
NSLog(@"%@",malloBlock);
.......................
<__NSStackBlock__: 0x7ffee6c473f8>
當block出棧就會銷毀的時候為 __NSStackBlock__
贺待,block為函數(shù)參數(shù)是也是 __NSStackBlock__
。
- 位于棧區(qū)
- 與MallocBlock一樣零截,可以在Block內(nèi)部使用局部變量或者OC屬性麸塞,但是不能賦值給強引用或者Copy修飾。
block的循環(huán)引用
對象A持有對象B涧衙,對象B又持有對象A哪工,相互持有奥此,最終導致兩個對象都不能釋放。
@interface ViewController ()
@property(nonatomic,copy)void(^blockA)(void);
@property (nonatomic, copy) NSString *name;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 循環(huán)引用
self.name = @"AAA";
self.blockA = ^{
NSLog(@"%@",self.name);
};
self.blockA();
}
@end
- (void)dealloc{
NSLog(@"dealloc 來了");
}
在這里雁比,self持有block稚虎,block里又對self進行了持有,導致循環(huán)引用偎捎,dealloc不會打印蠢终。
循環(huán)引用的解決方案
-
__weak
、__strong
__weak typeof(self) weakSelf = self;
self.blockA = ^{
NSLog(@"%@",weakSelf.name);
};
self.blockA();
原來是self->block->self
,現(xiàn)在變成了self->block->weakSelf->self
茴她,
將block中的self交給weakSelf,weakSelf在block結束時就會釋放,我們可以通過CFGetRetainCount((__bridge CFTypeRef)(self))
打印當前引用計數(shù)寻拂,發(fā)現(xiàn)self引用計數(shù)并沒有增加。
但是只用 __weak
還會存在問題
__weak typeof(self) weakSelf = self;
self.block = ^(void){
// 時間 - 精力
// self 的生命周期
__strong __typeof(weakSelf)strongSelf = weakSelf; // 可以釋放 when
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",strongSelf.name);
});
};
self.block();
當存在延時運行的時候丈牢,block結束時weakSelf還沒調用就被釋放了祭钉。self的生命周期沒有得到保存。這個時候就需要__strong
對其進行強引用己沛,strongSelf
是臨時變量慌核,在除了作用空間就會被釋放掉。weak-strong 強弱共舞
__block
__block ViewController *vc = self;
self.block = ^(void){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",vc.name);
vc = nil;
});
};
self.block();
我們除了__weak
自動釋放還可以通過__block
手動釋放泛粹,通過__block 修飾之后可以在block中修改值遂铡,通過手動的方式銷毀,但這里有個問題晶姊,如果block沒有調用的話扒接,就不會釋放,因為self被block捕獲了们衙,沒有調用所以無法釋放钾怔。
3.修改通信模式
因為當前self是被持有的,但我們可以通過通知蒙挑、代理宗侦、傳參的方式將self傳入。
self.block = ^(ViewController *vc){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",vc.name);
});
};
self.block(self);
當前self就會當做臨時變量壓棧進來忆蚀。
block編譯
1.block的基本實現(xiàn)
新建一個文件矾利,實現(xiàn)以下代碼
#include "stdio.h"
int main(){
__block int a = 11;
void(^block)(void) = ^{
a++;
printf("LG_Cooci - %d",a);
};
// block();
return 0;
}
通過xclang -arch x86_64 -rewrite-objc block.c
將其編譯成cpp文件
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("aaaa");
}
int main(){
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
return 0;
}
可以看到block被轉換成了__main_block_impl_0
結構體。通過構造方法馋袜,block函數(shù)被編譯成函數(shù)男旗,作為參數(shù)參入impl.FuncPtr = fp
,后面通過block->FuncPtr(block)
調用block欣鳖。block作為參數(shù)傳入當前函數(shù)中察皇,和oc方法一樣,作為隱藏參數(shù)泽台,可以更好地操作block什荣,可以對block對其進行操作矾缓。
- __block
我們先傳入一個普通的參數(shù)a
#include "stdio.h"
int main(){
int a = 10;
void(^block)(void) = ^{
printf("aaaa-%d",a);
};
block();
return 0;
}
clang
編譯一下
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int a;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int a = __cself->a; // bound by copy
printf("aaaa-%d",a);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(){
int a = 10;
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
return 0;
}
可以看到在編譯時就在block中自動生成了相應的變量a
,通過構造方法賦值稻爬。isa
指向為_NSConcreteStackBlock
嗜闻。在方法中直接出去a的值來操作,但是由于是賦值拷貝因篇,所以無法修改外部變量泞辐,會造成代碼歧義笔横。
現(xiàn)在我們加入__block
int main(){
__block int a = 10;
void(^block)(void) = ^{
a++;
printf("aaaa-%d",a);
};
block();
return 0;
}
clang
編譯一下
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__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_a_0 *a = __cself->a; // bound by ref
(a->__forwarding->a)++;
printf("aaaa-%d",(a->__forwarding->a));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(){
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {
(void*)0,
(__Block_byref_a_0 *)&a,
0,
sizeof(__Block_byref_a_0),
10};
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
return 0;
}
在這里生成了一個__Block_byref_a_0
結構體
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
};
將a封裝成相應的對象竞滓,通過地址拷貝傳遞到block函數(shù)中去,對其進行操作吹缔。
block底層原理
block源碼調試
我們現(xiàn)在block聲明的地方打上斷點商佑,然后Debug Workflow
-> Alaways Show Diassembly
查看匯編。
加他條件斷點厢塘,可以看到
libsystem_blocks.dylib _Block_copy
我們就可以找到block源碼進行查看
我們通過源碼可以看到所有的參數(shù)都來源于
Block_layout
struct Block_layout {
void *isa;
volatile int32_t flags; // contains ref count
int32_t reserved;
BlockInvokeFunction invoke;
struct Block_descriptor_1 *descriptor; //
// imported variables
};
flags
作為標識碼標識了當前的一些標志
// Values for Block_layout->flags to describe block objects
enum {
BLOCK_DEALLOCATING = (0x0001), // runtime 是否正在析構
BLOCK_REFCOUNT_MASK = (0xfffe), // runtime 引用計數(shù)的MASK
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 是否為全局GLOBAL
BLOCK_USE_STRET = (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30), // compiler 是否有簽名
BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31) // compiler
};
Block_descriptor
除了Block_descriptor_1
還有Block_descriptor_2
茶没、Block_descriptor_3
#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {
uintptr_t reserved;
uintptr_t size;
};
// 可選
#define BLOCK_DESCRIPTOR_2 1
struct Block_descriptor_2 {
// requires BLOCK_HAS_COPY_DISPOSE
BlockCopyFunction copy;
BlockDisposeFunction dispose;
};
#define BLOCK_DESCRIPTOR_3 1
struct Block_descriptor_3 {
// requires BLOCK_HAS_SIGNATURE
const char *signature;
const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT
};
Block_descriptor_1
是一直存在的,而Block_descriptor_2
晚碾、Block_descriptor_3
就是通過flags
來決定是否存在
#if 0
static struct Block_descriptor_1 * _Block_descriptor_1(struct Block_layout *aBlock)
{
return aBlock->descriptor;
}
#endif
static struct Block_descriptor_2 * _Block_descriptor_2(struct Block_layout *aBlock)
{
if (! (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)) return NULL;
uint8_t *desc = (uint8_t *)aBlock->descriptor;
desc += sizeof(struct Block_descriptor_1);
return (struct Block_descriptor_2 *)desc;
}
static struct Block_descriptor_3 * _Block_descriptor_3(struct Block_layout *aBlock)
{
if (! (aBlock->flags & BLOCK_HAS_SIGNATURE)) return NULL;
uint8_t *desc = (uint8_t *)aBlock->descriptor;
desc += sizeof(struct Block_descriptor_1);
if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE) {
desc += sizeof(struct Block_descriptor_2);
}
return (struct Block_descriptor_3 *)desc;
}
如果flags
顯示存在抓半,就找到aBlock->descriptor 通過內(nèi)存平移去找到Block_descriptor_2
、Block_descriptor_3
格嘁。
我們可以通過lldb register read
查看x0地址變化笛求,發(fā)現(xiàn)在_Block_copy
__NSStackBlock__
變?yōu)榱?code>__NSMallocBlock__
// Copy, or bump refcount, of a block. If really copying, call the copy helper if present.
// 棧 -> 堆 研究拷貝
void *_Block_copy(const void *arg) {
struct Block_layout *aBlock;
if (!arg) return NULL;
// The following would be better done as a switch statement
//拷貝當前的block防止對外層的影響
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.
struct Block_layout *result =
(struct Block_layout *)malloc(aBlock->descriptor->size);
if (!result) return NULL;
//內(nèi)存拷貝
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
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;
}
}
block 是怎么對外界變量進行操作的
int main(int argc, char * argv[]) {
@autoreleasepool {
__block NSString *a = [NSString stringWithFormat:@"aaa"];
void(^block)(void) = ^{
a = @"xxx";
printf("aaaa-%@",a);
};
block();
}
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
NSString *a;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__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_a_0 *a = __cself->a; // bound by ref
(a->__forwarding->a) = (NSString *)&__NSConstantStringImpl__var_folders__2_948tyv6520110qy_phw9x4fw0000gn_T_main_076a95_mi_1;
printf("aaaa-%@",(a->__forwarding->a));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
int main(int argc, char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 33554432, sizeof(__Block_byref_a_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSString * _Nonnull (*)(id, SEL, NSString * _Nonnull, ...))(void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders__2_948tyv6520110qy_phw9x4fw0000gn_T_main_076a95_mi_0)};
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));
}
static __NSConstantStringImpl __NSConstantStringImpl__var_folders__2_948tyv6520110qy_phw9x4fw0000gn_T_main_076a95_mi_0 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"aaa",3};
static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}
static __NSConstantStringImpl __NSConstantStringImpl__var_folders__2_948tyv6520110qy_phw9x4fw0000gn_T_main_076a95_mi_1 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"xxx",3};
這是生成的descriptor的糕簿,我們在descriptor_2
可以看到
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);}
我們?nèi)ゲ榭?code>_Block_object_assign源碼
void _Block_object_assign(void *destArg, const void *object, const int flags) {
const void **dest = (const void **)destArg;
switch (os_assumes(flags & BLOCK_ALL_COPY_DISPOSE_FLAGS)) {
case BLOCK_FIELD_IS_OBJECT:
/*******
id object = ...;
[^{ object; } copy];
********/
// objc 指針地址 weakSelf (self)
// arc 進行處理
_Block_retain_object(object);
// 持有
*dest = object;
break;
case BLOCK_FIELD_IS_BLOCK:
/*******
void (^object)(void) = ...;
[^{ object; } copy];
********/
// block 被一個 block 捕獲
*dest = _Block_copy(object);
break;
case BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK:
case BLOCK_FIELD_IS_BYREF:
/*******
// copy the onstack __block container to the heap
// Note this __weak is old GC-weak/MRC-unretained.
// ARC-style __weak is handled by the copy helper directly.
__block ... x;
__weak __block ... x;
[^{ x; } copy];
********/
*dest = _Block_byref_copy(object);
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK:
/*******
// copy the actual field held in the __block container
// Note this is MRC unretained __block only.
// ARC retained __block is handled by the copy helper directly.
__block id object;
__block void (^object)(void);
[^{ object; } copy];
********/
*dest = object;
break;
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK:
case BLOCK_BYREF_CALLER | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_WEAK:
/*******
// copy the actual field held in the __block container
// Note this __weak is old GC-weak/MRC-unretained.
// ARC-style __weak is handled by the copy helper directly.
__weak __block id object;
__weak __block void (^object)(void);
[^{ object; } copy];
********/
*dest = object;
break;
default:
break;
}
}
通過flag分為以下幾種類型
enum {
// see function implementation for a more complete description of these fields and combinations
BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ...
BLOCK_FIELD_IS_BLOCK = 7, // a block variable
BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable
BLOCK_FIELD_IS_WEAK = 16, // declared __weak, only used in byref copy helpers
BLOCK_BYREF_CALLER = 128, // called from __block (byref) copy/dispose support routines.
};
我們常用的為BLOCK_FIELD_IS_OBJECT
和BLOCK_FIELD_IS_BYREF
探入。
-
BLOCK_FIELD_IS_OBJECT
時什么都沒做,交給ARC進行處理懂诗。 BLOCK_FIELD_IS_BYREF
static struct Block_byref *_Block_byref_copy(const void *arg) {
// Block_byref 結構體
// 保存一份
struct Block_byref *src = (struct Block_byref *)arg;
if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
// src points to stack
struct Block_byref *copy = (struct Block_byref *)malloc(src->size);
copy->isa = NULL;
// byref value 4 is logical refcount of 2: one for caller, one for stack
copy->flags = src->flags | BLOCK_BYREF_NEEDS_FREE | 4;
// 問題 - block 內(nèi)部 持有的 Block_byref 所持有的對象 同一個
//拷貝的對象和原有的對象修改的是同一個內(nèi)存地址
copy->forwarding = copy; // patch heap copy to point to itself
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
if (src->flags & BLOCK_BYREF_HAS_COPY_DISPOSE) {
// Trust copy helper to copy everything of interest
// If more than one field shows up in a byref block this is wrong XXX
struct Block_byref_2 *src2 = (struct Block_byref_2 *)(src+1);
struct Block_byref_2 *copy2 = (struct Block_byref_2 *)(copy+1);
copy2->byref_keep = src2->byref_keep;
copy2->byref_destroy = src2->byref_destroy;
if (src->flags & BLOCK_BYREF_LAYOUT_EXTENDED) {
struct Block_byref_3 *src3 = (struct Block_byref_3 *)(src2+1);
struct Block_byref_3 *copy3 = (struct Block_byref_3*)(copy2+1);
copy3->layout = src3->layout;
}
(*src2->byref_keep)(copy, src);
}
else {
// Bitwise copy.
// This copy includes Block_byref_3, if any.
memmove(copy+1, src+1, src->size - sizeof(*src));
}
}
// already copied to heap
else if ((src->forwarding->flags & BLOCK_BYREF_NEEDS_FREE) == BLOCK_BYREF_NEEDS_FREE) {
latching_incr_int(&src->forwarding->flags);
}
return src->forwarding;
}
一開始就對當前參數(shù)進行拷貝蜂嗽,將拷貝的和原來的forwarding
指向同一個地址,這里的byref_keep
就是__Block_byref_id_object_copy_131
static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
dst + 40
指向的就是__Block_byref_a_0
種的a
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
NSString *a;
};
這只_Block_object_assign
指向的就是BLOCK_FIELD_IS_OBJECT
,對NSObject進行copy殃恒。
- 通過
_Block_copy
對block進行copy- __block byref 對結構體進行拷貝 _Block_object_assign
- 對結構體中的對象進行_Block_object_assign
如果參數(shù)是block會一層層拷貝下去