主要分析了block在持有__block呜魄、__weak、__strong修飾的對(duì)象時(shí)步绸,block結(jié)構(gòu)發(fā)生的變化尝丐。
以及block對(duì)持有變量的引用計(jì)數(shù)造成的具體影響显拜。
思考:
@implementation TestCode
- (void)testFunc {
@weakify(self)
self.block111 = ^{
@strongify(self);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self) {
printf("\n\nstrongPerson1 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
}else{
printf("self Retain Count = 0 \n");
}
});
};
}
- (void)dealloc {
printf("\n");
printf("? 【dealloc】 Retain Count = 0");
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
TestCode *t = [[TestCode alloc]init];
[t testFunc];
if (t.block111) {
t.block111();
}
}
@end
注意: 以下block111是self所持有的block
如果在
block111
中對(duì)NSMutableArray *arrayM
進(jìn)行增刪元素,arrayM
是否需要用__block
修飾?-
在
block111
中對(duì)weakSelf
進(jìn)行__strong typeof(weakSelf) strongSelf = weakSelf
修飾- 如果
block
一直不調(diào)用爹袁,那么self
是否可以正常銷毀远荠? - 當(dāng)運(yùn)行到
__strong typeof(weakSelf) strongSelf = weakSelf
的下一行時(shí),self
引用計(jì)數(shù)最少
是多少失息?
- 如果
一:基本介紹
定義
Block 是帶有自動(dòng)變量(局部變量)的匿名函數(shù)譬淳, 是 C
語言的擴(kuò)充功能,其本質(zhì)是一個(gè)OC
對(duì)象盹兢。
-
作為屬性
@property (nonatomic,copy) void(^block)(void);
-
作為參數(shù)
- (void) getDataWithBlock:(id(^)(id parameter))block;
-
作為返回值(masonry)
- (MASConstraint * (^)(id))equalTo
結(jié)構(gòu)
- (void)testFunc {
self.block111 = ^{
printf("block測試代碼");
};
self.block111();
}
把OC
代碼轉(zhuǎn)成c++
代碼
clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -fobjc-arc -fobjc-runtime=macosx-10.13 xxxxxx.m
static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
/// self.block = &__TestCode__testFunc_block_impl_0(A,B)
((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)
((id)self, sel_registerName("setBlock111:"),
(
(void (*)())&__TestCode__testFunc_block_impl_0
(
(void *)__TestCode__testFunc_block_func_0,// 參數(shù)1
&__TestCode__testFunc_block_desc_0_DATA// 參數(shù)2__TestCode__testFunc_block_desc_0,
)
)
);
((void (*(*)(id, SEL))())(void *)objc_msgSend)((id)self, sel_registerName("block111"))();
}
上段代碼的基本意思是
-
self.block = &__TestCode__testFunc_block_impl_0(A,B)
- A:
__TestCode__testFunc_block_func_0
- B:
__TestCode__testFunc_block_desc_0_DATA
- A:
1. __TestCode__testFunc_block_impl_0
struct __TestCode__testFunc_block_impl_0 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_0* Desc;
__TestCode__testFunc_block_impl_0(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
命名規(guī)律:_類名_方法名_block_impl_層級(jí)
上述代碼中可以看出block
被編譯成了__TestCode__testFunc_block_impl_0
結(jié)構(gòu)體
- 其內(nèi)部有一個(gè)同名的構(gòu)造函數(shù)
__TestCode__testFunc_block_impl_0
- 兩個(gè)屬性
__block_impl impl
__TestCode__testFunc_block_desc_0* Desc
2. __block_impl
struct __block_impl {
void *isa;// 指向了&_NSConcreteStackBlock
int Flags;
int Reserved;
void *FuncPtr; // 用于方法的儲(chǔ)存本質(zhì)是一個(gè) __TestCode__testFunc_block_func_0 c函數(shù)
};
可以發(fā)現(xiàn)__block_impl結(jié)構(gòu)體內(nèi)部就有一個(gè)isa指針邻梆。因此可以證明block本質(zhì)上就是一個(gè)oc對(duì)象。
__block_impl結(jié)構(gòu)體中isa指針存儲(chǔ)著&_NSConcreteStackBlock地址绎秒,可以暫時(shí)理解為其類對(duì)象地址浦妄,block就是_NSConcreteStackBlock類型的。
- 看到isa就會(huì)聯(lián)想到之前在objc_class結(jié)構(gòu)體见芹,因此我們的block本質(zhì)上也是一個(gè)對(duì)象【而且是個(gè)類對(duì)象】
我們知道實(shí)例對(duì)象->類對(duì)象->元類構(gòu)成了isa鏈中的一條剂娄,而這個(gè)__block_impl結(jié)構(gòu)體占據(jù)的是中間類對(duì)象的位置- 這里的isa指針會(huì)指向元類,這里的元類主要是為了說明這個(gè)塊的存儲(chǔ)區(qū)域
__TestCode__testFunc_block_func_0
static void __TestCode__testFunc_block_func_0(struct __TestCode__testFunc_block_impl_0 *__cself) {
printf("block測試代碼");
}
__TestCode__testFunc_block_func_0
中存放的是block中的代碼
3. __TestCode__testFunc_block_desc_0
static struct __TestCode__testFunc_block_desc_0 {
size_t reserved;
size_t Block_size;
} __TestCode__testFunc_block_desc_0_DATA = { 0, sizeof(struct __TestCode__testFunc_block_impl_0)};
主要是存儲(chǔ)了block
的大小
4. 同名的構(gòu)造函數(shù)__TestCode__testFunc_block_impl_0(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, int flags=0)
__TestCode__testFunc_block_impl_0
(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, int flags=0)
{
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
同名函數(shù)主要對(duì)兩個(gè)屬性進(jìn)行了賦值
-
void *fp
就是(void *)__TestCode__testFunc_block_func_0__
-
__ struct __TestCode__testFunc_block_desc_0 *desc
就是&__TestCode__testFunc_block_desc_0_DATA
5. 結(jié)構(gòu)圖
二:持有變量時(shí)block的結(jié)構(gòu)
以上分析的是 block
不持有任何外部變量玄呛,但是當(dāng)block
持有外部變量的時(shí)候宜咒,就會(huì)額外生成一些東西。
持有基本數(shù)據(jù)類型
持有的基本數(shù)據(jù)類型分為是否用__block
修飾把鉴,如下,a
用__block
修飾儿咱,b
沒有庭砍。
- (void)testFunc {
__block NSInteger a = 0;
NSInteger b = 0;
self.block111 = ^{
a = 12 + b;
printf("block測試代碼");
};
self.block111();
}
思考
a
用__block
修飾后可以修改,必然a
從值傳遞混埠,變成了地址傳遞怠缸。
-
__blok
把a
封裝成了什么結(jié)構(gòu)? - 結(jié)構(gòu)
a
的值到底存在哪里钳宪? - 結(jié)構(gòu)
a
是怎么管理內(nèi)存的揭北?
要回答上述問題扳炬,我們需要查看- (void)testFunc{}
編譯的源碼:
編譯后:
static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
// 結(jié)構(gòu)體 a 的生成 (__block NSInteger a = 0;)
__attribute__((__blocks__(byref))) __Block_byref_a_0 a =
{
(void*)0, // isa
(__Block_byref_a_0 *)&a,// a地址的傳遞
0,// flags
sizeof(__Block_byref_a_0),// size
0// a的值
};
NSInteger b = 0;
((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)
((id)self, sel_registerName("setBlock111:"),
/// 初始化__TestCode__testFunc_block_impl_0結(jié)構(gòu)體
((void (*)())&__TestCode__testFunc_block_impl_0
(
(void *)__TestCode__testFunc_block_func_0,
&__TestCode__testFunc_block_desc_0_DATA,
b,//值傳遞b
(__Block_byref_a_0 *)&a,//把結(jié)構(gòu)體(對(duì)象)a的地址傳了進(jìn)去
570425344
))
);
((void (*(*)(id, SEL))())(void *)objc_msgSend)((id)self, sel_registerName("block111"))();
}
1. __Block_byref_a_0
struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
NSInteger a;
};
// 結(jié)構(gòu)體 a 的生成
__attribute__((__blocks__(byref))) __Block_byref_a_0 a =
{
(void*)0, // isa
(__Block_byref_a_0 *)&a,// a地址的傳遞
0,// flags
sizeof(__Block_byref_a_0),// size
0// a的值
};
- 用了
__block
修飾的a
,生成了一個(gè)用__attribute__ 修飾的__Block_byref_a_0
類型的結(jié)構(gòu)體搔体。 - 結(jié)構(gòu)體內(nèi)部有一個(gè)
isa
指針,說明__Block_byref_a_0
其本質(zhì)也是一個(gè)OC
對(duì)象
2. __TestCode__testFunc_block_impl_0結(jié)構(gòu)體
struct __TestCode__testFunc_block_impl_0 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_0* Desc;
NSInteger b;
__Block_byref_a_0 *a; // by ref
// 同名的構(gòu)造函數(shù)
__TestCode__testFunc_block_impl_0
(
void *fp,
struct __TestCode__testFunc_block_desc_0 *desc,
NSInteger _b,
__Block_byref_a_0 *_a,
int flags=0
) : b(_b), a(_a->__forwarding) { ... }
};
生成了新的屬性:
-
NSInteger b
-
_b
就是棧區(qū)的b
-
b
值傳遞
-
-
__Block_byref_a_0 *a
由于賦值到
__TestCode__testFunc_block_impl_0
時(shí)恨樟,傳遞的是 棧區(qū)的__Block_byref_a_0 a
的地址,所以_a
==&a
。因?yàn)?code>_a->__forwarding就是
&_a
因此__TestCode__testFunc_block_impl_0
結(jié)構(gòu)體中的a
指向的就是棧中的a
小結(jié)論:
-
block
中的b
和外部的b
,只是值傳遞疚俱,因此即便外部修改了b
的值劝术,也不會(huì)對(duì)block
的b
產(chǎn)生影響。 -
__block a;
把a
包裝成了一個(gè)結(jié)構(gòu)體,而block
內(nèi)部屬性__Block_byref_a_0 *a
就是棧區(qū)結(jié)構(gòu)體a
的地址 - 此時(shí)呆奕,
block
沒有copy
操作养晋,所以block
存在棧區(qū),結(jié)構(gòu)體a
也存在棧區(qū)
3. __TestCode__testFunc_block_desc_0
static struct __TestCode__testFunc_block_desc_0 {
size_t reserved;
size_t Block_size;
//copy 函數(shù)
void (*copy)(
struct __TestCode__testFunc_block_impl_0*,
struct __TestCode__testFunc_block_impl_0*
);
// dispose 函數(shù)
void (*dispose)(struct __TestCode__testFunc_block_impl_0*);
} __TestCode__testFunc_block_desc_0_DATA =
{ 0,// reserved
sizeof(struct __TestCode__testFunc_block_impl_0), //size
__TestCode__testFunc_block_copy_0,//copy
__TestCode__testFunc_block_dispose_0//dispose
};
生成了 copy
dispose
函數(shù)
a. __TestCode__testFunc_block_copy_0
block
被拷貝到堆區(qū)的時(shí)候調(diào)用實(shí)現(xiàn)函數(shù)是
_Block_object_assign
梁钾,它根據(jù)對(duì)象的flags
來判斷是否需要拷貝绳泉,或者只是賦值。
// copy
static void __TestCode__testFunc_block_copy_0(struct __TestCode__testFunc_block_impl_0*dst, struct __TestCode__testFunc_block_impl_0*src){
_Block_object_assign(
(void*)&dst->a,
(void*)src->a,
8/*BLOCK_FIELD_IS_BYREF*/
);
}
_Block_object_assign
函數(shù)實(shí)現(xiàn)在 runtime.c
里
/**
_Block_object_assign參數(shù)flag相關(guān)
// 是一個(gè)對(duì)象
BLOCK_FIELD_IS_OBJECT = 3,
// 是一個(gè)block
BLOCK_FIELD_IS_BLOCK = 7,
// 被__block修飾的變量
BLOCK_FIELD_IS_BYREF = 8,
// 被__weak修飾的變量姆泻,只能被輔助copy函數(shù)使用
BLOCK_FIELD_IS_WEAK = 16,
// block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
BLOCK_BYREF_CALLER = 128
**/
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
// BLOCK_BYREF_CALLER block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
//BLOCK_FIELD_IS_WEAK 被__weak修飾的變量零酪,只能被輔助copy函數(shù)使用
if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
_Block_assign_weak(object, destAddr);
}
else {
_Block_assign((void *)object, destAddr);
}
}
// 被__block修飾的變量
else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
///最終走到這邊
_Block_byref_assign_copy(destAddr, object, flags);
}
// 是一個(gè)block
else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
_Block_assign(_Block_copy_internal(object, flags), destAddr);
}
// 是一個(gè)對(duì)象
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
_Block_retain_object(object);
_Block_assign((void *)object, destAddr);
}
}
/*
Block_private.h
https://opensource.apple.com/source/libclosure/libclosure-73/Block_private.h
*/
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 Block_byref {
void *isa;
struct Block_byref *forwarding;
int flags; /* refcount; */
int size;
};
/** runtime.c
http://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/BlocksRuntime/runtime.c
*/
static void *_Block_copy_class = _NSConcreteMallocBlock;
static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
static int _Block_copy_flag = BLOCK_NEEDS_FREE;
static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
struct Block_byref **destp = (struct Block_byref **)dest;
struct Block_byref *src = (struct Block_byref *)arg;
//不需要做任何操作
if (src->forwarding->flags & BLOCK_IS_GC) {
}
// 需要copy到堆區(qū) 并且需要操作引用計(jì)數(shù)
else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
// src points to stack
bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
// if its weak ask for an object (only matters under GC)
struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
if (isWeak) {
copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning
}
if (src->flags & BLOCK_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
copy->byref_keep = src->byref_keep;
copy->byref_destroy = src->byref_destroy;
(*src->byref_keep)(copy, src);
}
else {
// just bits. Blast 'em using _Block_memmove in case they're __strong
_Block_memmove(
(void *)©->byref_keep,
(void *)&src->byref_keep,
src->size - sizeof(struct Block_byref_header));
}
}
// 已經(jīng)復(fù)制到堆、只操作引用計(jì)數(shù)
else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
latching_incr_int(&src->forwarding->flags);
}
// assign byref data block pointer into new Block
// 其實(shí)進(jìn)行了 *destp = src->forwarding 操作麦射,把棧區(qū)的a蛾娶,變成了 Block_byref *copy
_Block_assign(src->forwarding, (void **)destp);
}
static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
static void _Block_assign_default(void *value, void **destptr) {
*destptr = value;
}
省略后的代碼
struct Block_byref {
void *isa;
struct Block_byref *forwarding;
int flags; /* refcount; */
int size;
};
static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
...
struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
// 堆中拷貝的forwarding指向它自己
copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
// 棧中的forwarding指向堆中的新對(duì)象
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
...
// 其實(shí)進(jìn)行了 *destp = src->forwarding 操作,把棧區(qū)的a潜秋,變成了 Block_byref *copy
_Block_assign(src->forwarding, (void **)destp);
}
可以看到蛔琅,Block_byref
和 __Block_byref_a_0
的前4
個(gè)成員類型相同,可以互相轉(zhuǎn)化峻呛。
b. __TestCode__testFunc_block_dispose_0
// dispose
static void __TestCode__testFunc_block_dispose_0(struct __TestCode__testFunc_block_impl_0*src){
_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);
}
_Block_object_dispose
void _Block_object_dispose(const void *object, const int flags) {
//printf("_Block_object_dispose(%p, %x)\n", object, flags);
if (flags & BLOCK_FIELD_IS_BYREF) {
// 釋放 __block 修飾的變量
_Block_byref_release(object);
}
else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
// 釋放block 引用的 block
_Block_destroy(object);
}
else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
// 釋放block 引用的對(duì)象
_Block_release_object(object);
}
}
static void _Block_byref_release(const void *arg) {
struct Block_byref *shared_struct = (struct Block_byref *)arg;
int refcount;
shared_struct = shared_struct->forwarding;
if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
return; // stack or GC or global
}
refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
if (refcount <= 0) {
printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
}
else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
(*shared_struct->byref_destroy)(shared_struct);
}
_Block_deallocator((struct Block_layout *)shared_struct);
}
}
static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
static int latching_decr_int(int *where) {
while (1) {
int old_value = *(volatile int *)where;
if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
return BLOCK_REFCOUNT_MASK;
}
if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
return 0;
}
if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
return old_value-1;
}
}
}
被__block
修飾的變量罗售,釋放時(shí)要用 latching_decr_int
函數(shù)減引用計(jì)數(shù),直到計(jì)數(shù)為0
钩述,就釋放該對(duì)象寨躁;
而普通的對(duì)象、block
牙勘,就直接釋放銷毀职恳。
小結(jié):
生成了
copy
despose
函數(shù)。-
copy
調(diào)用時(shí)機(jī):- 當(dāng)
block
進(jìn)行copy
操作的時(shí)候就會(huì)自動(dòng)調(diào)用__TestCode__testFunc_block_desc_0
內(nèi)部的__TestCode__testFunc_block_copy_0
函數(shù)方面,__TestCode__testFunc_block_copy_0
函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign
函數(shù)放钦。 -
_Block_object_assign
內(nèi)部是根據(jù)傳遞的flags
類型來對(duì)a
進(jìn)行copy
、retain
操作
- 當(dāng)
-
despose
調(diào)用時(shí)機(jī):- 當(dāng)
block
從堆中移除時(shí)就會(huì)自動(dòng)調(diào)用__TestCode__testFunc_block_desc_0
中__TestCode__testFunc_block_dispose_0
函數(shù)恭金,__TestCode__testFunc_block_dispose_0
函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose
函數(shù)操禀。 -
_Block_object_dispose
會(huì)對(duì)a
做釋放操作,類似于release
横腿。
- 當(dāng)
4. __TestCode__testFunc_block_func_0
__TestCode__testFunc_block_func_0
是__block_impl
結(jié)構(gòu)體中存儲(chǔ)的block
代碼
static void __TestCode__testFunc_block_func_0(struct __TestCode__testFunc_block_impl_0 *__cself) {
__Block_byref_a_0 *a = __cself->a; // bound by ref
NSInteger b = __cself->b; // bound by copy
(a->__forwarding->a) = 12 + b;
printf("block測試代碼");
}
__cself
就是我們定義的block
a->__forwarding
其實(shí)修改的就是我們堆區(qū)的(Block_byref) copy
(注意 在ARC下我們的block會(huì)自動(dòng)copy)
下圖在TestCode.m中自定義了結(jié)構(gòu)體:
struct __Block_byref_a_0 { void *__isa; struct __Block_byref_a_0 *__forwarding; int __flags; int __size; NSInteger a; }; struct __block_impl { void *isa;// 指向了&_NSConcreteStackBlock int Flags; int Reserved; void *FuncPtr; // 用于方法的儲(chǔ)存本質(zhì)是一個(gè) __TestCode__testFunc_block_func_0 c函數(shù) }; struct __TestCode__testFunc_block_impl_0 { struct __block_impl impl; struct __TestCode__testFunc_block_desc_0* Desc; struct __Block_byref_a_0 *a; // by ref };
截屏2020-02-01下午4.30.11.png
5. 結(jié)構(gòu)圖
__block NSInteger a = 0;
NSInteger b = 0;
self.block111 = ^{
a = 12 + b;
printf("block測試代碼");
};
持有對(duì)象類型
對(duì)象類型的引用分為三種情況:
- 用
__block
修飾 - 用
__strong
修飾(@strongify) - 用
__weak
修飾 (@weakify)
??注意下面的代碼產(chǎn)生了循環(huán)引用颓屑,隨后會(huì)做詳細(xì)的分析
- (void)testFunc {
__weak typeof(self)weakSelf = self;
__block TestCode *blockSelf = weakSelf;
self.block111 = ^{
__strong typeof(weakSelf)strongSelf = weakSelf;
void(^block222)(void) = ^{
blockSelf = strongSelf;
printf("\nblock測試代碼\n");
};
block222();
};
self.block111();
}
編譯上述代碼:
static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
__attribute__((objc_ownership(weak))) typeof(self)weakSelf = self;
__attribute__((__blocks__(byref))) __Block_byref_blockSelf_0 blockSelf =
{
(void*)0,
(__Block_byref_blockSelf_0 *)&blockSelf,
33554432,
sizeof(__Block_byref_blockSelf_0),
__Block_byref_id_object_copy_131,
__Block_byref_id_object_dispose_131,
weakSelf
};
// 創(chuàng)建 __TestCode__testFunc_block_impl_1
((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)((id)self, sel_registerName("setBlock111:"), ((void (*)())&__TestCode__testFunc_block_impl_1
(//參數(shù):
(void *)__TestCode__testFunc_block_func_1,
&__TestCode__testFunc_block_desc_1_DATA,
weakSelf,
(__Block_byref_blockSelf_0 *)&blockSelf,
570425344)
));
((void (*(*)(id, SEL))())(void *)objc_msgSend)((id)self, sel_registerName("block111"))();
}
1. __Block_byref_blockSelf_0
struct __Block_byref_blockSelf_0 {
//【值為:0】[8個(gè)字節(jié)]
void *__isa;
//【值為&blockSelf】,[8個(gè)字節(jié)]
__Block_byref_blockSelf_0 *__forwarding;
int __flags;//【值為33554432】,[4個(gè)字節(jié)]
int __size;//【值為sizeof(__Block_byref_blockSelf_0)】,[4個(gè)字節(jié)]
//【__Block_byref_id_object_copy_131】[8個(gè)字節(jié)]
void (*__Block_byref_id_object_copy)(void*, void*);
//【__Block_byref_id_object_dispose_131】,[8個(gè)字節(jié)]
void (*__Block_byref_id_object_dispose)(void*);
TestCode *__strong blockSelf;//【weakSelf】[8個(gè)字節(jié)]
};
/// 共48個(gè)字節(jié)
self
使用__block
修飾后斤寂,blockPerson
被包裝成了一個(gè)與__Block_byref_a_0
相似的結(jié)構(gòu)體
只是比__Block_byref_a_0
多了兩個(gè)函數(shù):
-
__Block_byref_id_object_copy
值為__Block_byref_id_object_copy_131
-
__Block_byref_id_object_dispose
值為__Block_byref_id_object_dispose_131
??值得注意的是blockSelf
用了__strong
修飾,因此產(chǎn)生了循環(huán)引用揪惦!需要改成__block typeof(weakSelf)blockSelf = weakSelf;
下面會(huì)有詳細(xì)解釋
__Block_byref_id_object_copy_131 與 __Block_byref_id_object_dispose_131
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);
}
內(nèi)部調(diào)用函數(shù)為
_Block_object_assign
dst
與src
就是blockSelf
即__Block_byref_blockSelf_0
結(jié)構(gòu)體指針因
__Block_byref_blockSelf_0
共48個(gè)字節(jié)遍搞,所以(char*)dst + 40
與(char)src + 40
,找到的就是TestCode *__strong blockSelf
最后的
flags
傳遞的是131 = 3|128
即 :BLOCK_FIELD_IS_OBJECT
|BLOCK_FIELD_IS_CALLER
調(diào)用時(shí)機(jī):block
執(zhí)行copy
操作丹擎,后面會(huì)詳細(xì)分析尾抑。
2. __TestCode__testFunc_block_impl_1
struct __TestCode__testFunc_block_impl_1 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_1* Desc;
TestCode *const __weak weakSelf;
__Block_byref_blockSelf_0 *blockSelf; // by ref
__TestCode__testFunc_block_impl_1(
void *fp,
struct __TestCode__testFunc_block_desc_1 *desc,
TestCode *const __weak _weakSelf,
__Block_byref_blockSelf_0 *_blockSelf,
int flags=0
) : weakSelf(_weakSelf), blockSelf(_blockSelf->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
生成了兩個(gè)成員變量:Person *__weak weakPerson;
、__Block_byref_blockPerson_0 *blockPerson;
**a. __block_impl impl **
結(jié)構(gòu)沒有任何變化
-
flags
:570425344
表示BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR
蒂培,即(1<<25 | 1<<29) -
FuncPtr
:__TestCode__testFunc_block_func_1
3. __TestCode__testFunc_block_desc_1
結(jié)構(gòu)沒有任何變化
desc
:結(jié)構(gòu)體__TestCode__testFunc_block_desc_1_DATA
static struct __TestCode__testFunc_block_desc_1 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __TestCode__testFunc_block_impl_1*, struct __TestCode__testFunc_block_impl_1*);
void (*dispose)(struct __TestCode__testFunc_block_impl_1*);
} __TestCode__testFunc_block_desc_1_DATA = {
0,
sizeof(struct __TestCode__testFunc_block_impl_1),
__TestCode__testFunc_block_copy_1,
__TestCode__testFunc_block_dispose_1
};
值得注意的是:copy再愈、dispose的實(shí)現(xiàn)函數(shù)
// copy 函數(shù)
static void __TestCode__testFunc_block_copy_1(struct __TestCode__testFunc_block_impl_1*dst, struct __TestCode__testFunc_block_impl_1*src)
{
_Block_object_assign((void*)&dst->weakSelf, (void*)src->weakSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);
_Block_object_assign((void*)&dst->blockSelf, (void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);
}
// dispose 函數(shù)
static void __TestCode__testFunc_block_dispose_1(struct __TestCode__testFunc_block_impl_1*src)
{
_Block_object_dispose((void*)src->weakSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);
_Block_object_dispose((void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);
}
a. 對(duì)weakSelf
的 _Block_object_assign
操作
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
// BLOCK_BYREF_CALLER block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) { ... }
// 被__block修飾的變量
else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) { ... }
// 是一個(gè)block
else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { ... }
// 是一個(gè)對(duì)象
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
_Block_retain_object(object);
_Block_assign((void *)object, destAddr);
}
}
即直接對(duì)對(duì)象進(jìn)行一個(gè)_Block_retain_object
操作
但是發(fā)現(xiàn)在ARC下_Block_retain_object
函數(shù)并沒有給對(duì)象的引用計(jì)數(shù)+1。
static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
static void _Block_retain_object_default(const void *ptr) {
if (!ptr) return;
}
b. 對(duì)blockSelf
的_Block_object_assign
操作
最終會(huì)調(diào)用到_Block_byref_assign_copy
函數(shù)
static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
struct Block_byref **destp = (struct Block_byref **)dest;
struct Block_byref *src = (struct Block_byref *)arg;
//不需要做任何操作
if (src->forwarding->flags & BLOCK_IS_GC) {
}
// 需要copy到堆區(qū) 并且需要操作引用計(jì)數(shù)
else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
copy->flags = src->flags | _Byref_flag_initial_value;
copy->forwarding = copy;
src->forwarding = copy;
copy->size = src->size;
if (isWeak) {
copy->isa = &_NSConcreteWeakBlockVariable;
}
if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
/// 調(diào)用 __Block_byref_blockSelf_0 中的 __Block_byref_id_object_copy 函數(shù)
/// 執(zhí)行byref的byref_keep函數(shù)(即assign函數(shù)护戳,只是會(huì)加上BLOCK_BYREF_CALLER標(biāo)志)翎冲,管理捕獲的對(duì)象內(nèi)存
copy->byref_keep = src->byref_keep;
copy->byref_destroy = src->byref_destroy;
(*src->byref_keep)(copy, src);
}
else { ... }
}
// 已經(jīng)復(fù)制到堆、只操作引用計(jì)數(shù)
else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) { ... }
_Block_assign(src->forwarding, (void **)destp);
}
值得注意的是在Block_private.h找到了這個(gè)結(jié)構(gòu):
struct Block_byref {
void *isa;
struct Block_byref *forwarding;
volatile int32_t flags; // contains ref count
uint32_t size;
};
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;
};
其實(shí)byref_keep
就是blockSelf
中的__Block_byref_id_object_copy
也就是函數(shù)__Block_byref_id_object_copy_131
所以其調(diào)用為
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_copy_131(__Block_byref_blockSelf_0 *dst, __Block_byref_blockSelf_0 *src) {
_Block_object_assign(
dst->blockSelf,
*(void * )(src->blockSelf),
BLOCK_FIELD_IS_OBJECT|BLOCK_FIELD_IS_CALLER
);
}
繼續(xù)看_Block_object_assign
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
// BLOCK_BYREF_CALLER block輔助函數(shù)調(diào)用(告訴內(nèi)部實(shí)現(xiàn)不要進(jìn)行retain或者copy)
if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
//BLOCK_FIELD_IS_WEAK 被__weak修飾的變量媳荒,只能被輔助copy函數(shù)使用
if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
_Block_assign_weak(object, destAddr);
}
else {
_Block_assign((void *)object, destAddr);
}
}
else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) { ... }
else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { ... }
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) { ... }
}
static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
static void _Block_assign_default(void *value, void **destptr) {
*destptr = value;
}
運(yùn)行了_Block_assign
函數(shù)抗悍,把棧區(qū)的__Block_byref_blockSelf_0 blockSelf
賦值成了Block_byref copy
c. 對(duì)weakSelf
的 dispose
操作
static void __TestCode__testFunc_block_dispose_1(struct __TestCode__testFunc_block_impl_1*src)
{
_Block_object_dispose(
(void*)src->self,
3/*BLOCK_FIELD_IS_OBJECT*/
);
_Block_object_dispose(
(void*)src->blockSelf,
8/*BLOCK_FIELD_IS_BYREF*/
);
}
void _Block_object_dispose(const void *object, const int flags) {
if (flags & BLOCK_FIELD_IS_BYREF) { ... }
else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {...}
else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
// 釋放block 引用的對(duì)象
_Block_release_object(object);
}
}
static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
static void _Block_release_object_default(const void *ptr) {
if (!ptr) return;
}
可以看到:最終會(huì)調(diào)用到_Block_release_object
,內(nèi)部也是沒對(duì)引用計(jì)數(shù)進(jìn)行操作。
d. 對(duì)blockSelf
的 dispose
操作
其最終走到了_Block_byref_release
函數(shù):
static void _Block_byref_release(const void *arg) {
struct Block_byref *shared_struct = (struct Block_byref *)arg;
int refcount;
shared_struct = shared_struct->forwarding;
if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
return;
}
refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
if (refcount <= 0) { }
else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
/// 主要調(diào)用了
if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
(*shared_struct->byref_destroy)(shared_struct);
}
_Block_deallocator((struct Block_layout *)shared_struct);
}
}
其中__block_release
函數(shù)內(nèi)部主要是調(diào)用了(*shared_struct->byref_destroy)(shared_struct)
也就是 __Block_byref_blockSelf_0 *blockSelf
中的__Block_byref_id_object_dispose_131
函數(shù)
static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}
///譯為:
static void __Block_byref_id_object_dispose_131(__Block_byref_blockSelf_0 *src) {
_Block_object_dispose
(
*(void * *) (src->blockSelf),
BLOCK_FIELD_IS_OBJECT|BLOCK_FIELD_IS_CALLER
);
}
e. __TestCode__testFunc_block_func_1
查看__TestCode__testFunc_block_func_1
钳枕,函數(shù)中是如何創(chuàng)建第二層block222
的
{
__strong typeof(weakSelf)strongSelf = weakSelf;
void(^block222)(void) = ^{
blockSelf = strongSelf;
printf("\nblock測試代碼\n");
};
block222();
}
static void __TestCode__testFunc_block_func_1(struct __TestCode__testFunc_block_impl_1 *__cself) {
__Block_byref_blockSelf_0 *blockSelf = __cself->blockSelf; // bound by ref
TestCode *const __weak weakSelf = __cself->weakSelf; // bound by copy
///__strong typeof(weakSelf)strongSelf = weakSelf;
__attribute__((objc_ownership(strong))) typeof(weakSelf)strongSelf = weakSelf;
/// 創(chuàng)建block222 即:__TestCode__testFunc_block_impl_0結(jié)構(gòu)體
void(*block222)(void) = ((void (*)())&__TestCode__testFunc_block_impl_0((void *)__TestCode__testFunc_block_func_0,&__TestCode__testFunc_block_desc_0_DATA,strongSelf,(__Block_byref_blockSelf_0 *)blockSelf,570425344));
/// 調(diào)用: block222()
((void (*)(__block_impl *))((__block_impl *)block222)->FuncPtr)((__block_impl *)block222);
}
其中block222
是一個(gè)__TestCode__testFunc_block_impl_0
結(jié)構(gòu)體
4. __TestCode__testFunc_block_impl_0
struct __TestCode__testFunc_block_impl_0 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_0* Desc;
TestCode *const __strong strongSelf;
__Block_byref_blockSelf_0 *blockSelf; // by ref
__TestCode__testFunc_block_impl_0(
void *fp,
struct __TestCode__testFunc_block_desc_0 *desc,
TestCode *const __strong _strongSelf,
__Block_byref_blockSelf_0 *_blockSelf,
int flags=0
) : strongSelf(_strongSelf), blockSelf(_blockSelf->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
其結(jié)構(gòu)和__TestCode__testFunc_block_impl_1
結(jié)構(gòu)相似缴渊。
只不過blockSelf
就是上層block
(即:block111
)中的 blockSelf
值得注意的是這邊有個(gè)TestCode *const __strong strongSelf;
剩下的結(jié)構(gòu)與之前分析的結(jié)構(gòu)大同小異:
static void __TestCode__testFunc_block_func_0(struct __TestCode__testFunc_block_impl_0 *__cself) {
__Block_byref_blockSelf_0 *blockSelf = __cself->blockSelf; // bound by ref
TestCode *const __strong strongSelf = __cself->strongSelf; // bound by copy
(blockSelf->__forwarding->blockSelf) = strongSelf;
printf("\nblock測試代碼\n");
}
static void __TestCode__testFunc_block_copy_0(struct __TestCode__testFunc_block_impl_0*dst, struct __TestCode__testFunc_block_impl_0*src) {_Block_object_assign((void*)&dst->blockSelf, (void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_assign((void*)&dst->strongSelf, (void*)src->strongSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __TestCode__testFunc_block_dispose_0(struct __TestCode__testFunc_block_impl_0*src) {_Block_object_dispose((void*)src->blockSelf, 8/*BLOCK_FIELD_IS_BYREF*/);_Block_object_dispose((void*)src->strongSelf, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __TestCode__testFunc_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __TestCode__testFunc_block_impl_0*, struct __TestCode__testFunc_block_impl_0*);
void (*dispose)(struct __TestCode__testFunc_block_impl_0*);
} __TestCode__testFunc_block_desc_0_DATA = { 0, sizeof(struct __TestCode__testFunc_block_impl_0), __TestCode__testFunc_block_copy_0, __TestCode__testFunc_block_dispose_0};
三:持有變量引用計(jì)數(shù)操作:
既然在ARC
下copy
、dispose
函數(shù)都沒有對(duì)引用計(jì)數(shù)做修改鱼炒,那么什么時(shí)候會(huì)對(duì)引用計(jì)數(shù)進(jìn)行操作?
通過對(duì)持有變量的分析衔沼、可以總結(jié)出以下特點(diǎn)
1. 用__strong 與 __weak修飾
- (void)testFunc {
printf("\n Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
__weak typeof (self)weakSelf1 = self;
printf("\n 【__weak typeof (self)weakSelf】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
__weak TestCode *weakSelf2 = self;
printf("\n 【__weak TestCode *weakSelf2】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
__strong typeof(self)strongSelf1 = self;
printf("\n 【__strong typeof(self)strongSelf1】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
__strong TestCode *strongSelf2 = self;
printf("\n 【__strong TestCode *strongSelf2】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
self.block111 = ^{
[weakSelf1 class];
[weakSelf2 class];
[strongSelf1 class];
[strongSelf2 class];
};
}
/** log:
Retain Count = 1
【__weak typeof (self)weakSelf】 Retain Count = 1
【__weak TestCode *weakSelf2】 Retain Count = 1
【__strong typeof(self)strongSelf1】 Retain Count = 2
【__strong TestCode *strongSelf2】 Retain Count = 3
*/
編譯后的代碼:
static void _I_TestCode_testFunc(TestCode * self, SEL _cmd) {
printf("...");
__attribute__((objc_ownership(weak))) typeof (self)weakSelf1 = self;
__attribute__((objc_ownership(weak))) TestCode *weakSelf2 = self;
__attribute__((objc_ownership(strong))) typeof(self)strongSelf1 = self;
__attribute__((objc_ownership(strong))) TestCode *strongSelf2 = self;
((void (*)(id, SEL, void (^ _Nonnull)()))(void *)objc_msgSend)((id)self, sel_registerName("setBlock111:"), ((void (*)())&__TestCode__testFunc_block_impl_0((void *)__TestCode__testFunc_block_func_0, &__TestCode__testFunc_block_desc_0_DATA, strongSelf1, strongSelf2, 570425344)));
}
struct __TestCode__testFunc_block_impl_0 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_0* Desc;
TestCode *const __weak weakSelf1;
TestCode *__weak weakSelf2;
__strong typeof (self) strongSelf1;
TestCode *__strong strongSelf2;
// 同名構(gòu)造函數(shù)
__TestCode__testFunc_block_impl_0(...){ ... }
};
-
__weak
__weak TestCode *weakSelf1 = self
與__weak typeof(self)weakSelf2 = self
最終都調(diào)用了
__attribute__((objc_ownership(weak)))
而且
__TestCode__testFunc_block_impl_0
中對(duì)weakSelf1
和weakSelf2
都是弱引用 -
__strong
__strong typeof(self)strongSelf1 = self
與__strong TestCode *strongSelf2 = self
最終都調(diào)用了
__attribute__((objc_ownership(strong)))
而且
__TestCode__testFunc_block_impl_0
中對(duì)strongSelf1
和strongSelf2
都是強(qiáng)引用
2. 用__block
修飾的對(duì)象
用__block
修飾的對(duì)象分成兩種寫法
__block TestCode *blockSelf = weakSelf
__block typeof(weakSelf)blockSelf2 = weakSelf
- (void)testFunc {
printf("\n Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
__weak typeof(self)weakSelf = self;
__block TestCode *blockSelf1 = weakSelf;
printf("\n 【__block TestCode *blockSelf1 = weakSelf】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
__block typeof(weakSelf)blockSelf2 = weakSelf;
printf("\n 【__block typeof(weakSelf)blockSelf2 = weakSelf】 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
self.block111 = ^{
[blockSelf1 class];
[blockSelf2 class];
};
}
/**log:
Retain Count = 1
【__block TestCode *blockSelf1 = weakSelf】 Retain Count = 2
【__block typeof(weakSelf)blockSelf2 = weakSelf】 Retain Count = 2
*/
編譯上述代碼:
struct __TestCode__testFunc_block_impl_0 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_0* Desc;
__Block_byref_blockSelf1_0 *blockSelf1; // by ref
__Block_byref_blockSelf2_1 *blockSelf2; // by ref
// 同名構(gòu)造函數(shù)
__TestCode__testFunc_block_impl_0(...) { ... }
};
struct __Block_byref_blockSelf1_0 {
void *__isa;
__Block_byref_blockSelf1_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
TestCode *__strong blockSelf1;
};
struct __Block_byref_blockSelf2_1 {
void *__isa;
__Block_byref_blockSelf2_1 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
typeof (weakSelf) blockSelf2;
};
在__TestCode__testFunc_block_impl_0
中生成了兩個(gè)成員變量
-
__block TestCode *blockSelf = weakSelf
TestCode *__strong blockSelf1;
對(duì)self
進(jìn)行了強(qiáng)引用,從而self
引用計(jì)數(shù)+1,從而產(chǎn)生循環(huán)引用昔瞧。 -
__block typeof(weakSelf)blockSelf2 = weakSelf;
typeof (weakSelf) blockSelf2
對(duì)self
的引用為弱引用指蚁,引用計(jì)數(shù)沒有+1操作。
3. 補(bǔ)充:
- 在當(dāng)前作用域中自晰,對(duì)
self
的retainCount
加1凝化,退出作用域后減一__block typeof(self)blockSelf = self;
__block NSObject *blockSelf = self;
__strong typeof (self)strongSelf = self;
__strong NSObject *strongSelf = self;
- 對(duì)
self
的retainCount
不作操作__weak typeof(self)weakSelf = self;
__weak NSObject *weakSelf = self;
注意 :
用這些修飾語句對(duì)對(duì)象的引用計(jì)數(shù)只在當(dāng)前作用域有效。讓block
產(chǎn)生循環(huán)引用的關(guān)鍵在于
__TestCode__testFunc_block_impl_0
block結(jié)構(gòu)體中對(duì)對(duì)象是否是強(qiáng)引用酬荞。
思考答案
@implementation TestCode
- (void)testFunc {
@weakify(self)
self.block111 = ^{
@strongify(self);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self) {
printf("\n\nstrongPerson1 Retain Count = %ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
}else{
printf("self Retain Count = 0 \n");
}
});
};
}
- (void)dealloc {
printf("\n");
printf("? 【dealloc】 Retain Count = 0");
}
@end
編譯后代碼:
/// block111結(jié)構(gòu)體
struct __TestCode__testFunc_block_impl_1 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_1* Desc;
TestCode *const __weak self_weak_;// 若引用
__TestCode__testFunc_block_impl_1(void *fp, struct __TestCode__testFunc_block_desc_1 *desc, TestCode *const __weak _self_weak_, int flags=0) : self_weak_(_self_weak_) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
///block111中儲(chǔ)存的代碼
static void __TestCode__testFunc_block_func_1(struct __TestCode__testFunc_block_impl_1 *__cself) {
TestCode *const __weak self_weak_ = __cself->self_weak_; // bound by copy
try {} catch (...) {}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshadow"
__attribute__((objc_ownership(strong))) __typeof__(self) self = self_weak_;
#pragma clang diagnostic pop
;
dispatch_after(dispatch_time((0ull), (int64_t)(2.0 * 1000000000ull)), dispatch_get_main_queue(), ((void (*)())&__TestCode__testFunc_block_impl_0((void *)__TestCode__testFunc_block_func_0, &__TestCode__testFunc_block_desc_0_DATA, self, 570425344)));
}
/// block222結(jié)構(gòu)體
struct __TestCode__testFunc_block_impl_0 {
struct __block_impl impl;
struct __TestCode__testFunc_block_desc_0* Desc;
__strong typeof (self) self;/// 強(qiáng)引用
__TestCode__testFunc_block_impl_0(void *fp, struct __TestCode__testFunc_block_desc_0 *desc, __strong typeof (self) _self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
注意:以下block111是self所持有的block
-
如果在
block111
中對(duì)NSMutableArray *arrayM
進(jìn)行增刪元素,arrayM
是否需要用__block
修飾搓劫?答:不需要,因?yàn)椴]有修改
arrayM
指針?biāo)赶虻牡刂?/p>
-
在
block111
中對(duì)weakSelf
進(jìn)行__strong typeof(weakSelf) strongSelf = weakSelf
修飾-
如果
block
一直不調(diào)用混巧,那么self
是否可以正常銷毀糟把?答:可以銷毀
因?yàn)?code>block調(diào)用的時(shí)候,才會(huì)創(chuàng)建
__TestCode__testFunc_block_impl_0
使得
__TestCode__testFunc_block_impl_0
內(nèi)部對(duì)self
進(jìn)行了強(qiáng)引用從而只要
__TestCode__testFunc_block_impl_0
不銷毀牲剃,self
就無法銷毀 -
當(dāng)運(yùn)行到
__strong typeof(weakSelf) strongSelf = weakSelf
的下一行時(shí),self
引用計(jì)數(shù)最少
是多少雄可?答:最少是2
但是出了
__strong typeof(weakSelf) strongSelf = weakSelf
的作用域凿傅,self
的引用計(jì)數(shù)就會(huì)自動(dòng)減1
判斷void*是否為block類型
-
BOOL FBObjectIsBlock(void *object) {
Class blockClass = _BlockClass();
Class candidate = object_getClass((__bridge id)object);
return [candidate isSubclassOfClass:blockClass];
}
參考文章
- 探索 Block 的本質(zhì)
- iOS底層原理總結(jié) - 探尋block的本質(zhì)(一)
- iOS底層原理總結(jié) - 探尋block的本質(zhì)(二)
- iOS Block Part6:block拷貝的實(shí)現(xiàn)
- OS - Block底層解析
- 一篇文章剖析block底層源碼以及Block.private
- Block_private.h
- runtime.c
- iOS 中的 block 是如何持有對(duì)象的
如果有不對(duì)的地方歡迎來噴~