Block的本質
Block是將函數(shù)及其執(zhí)行上下文封裝起來的對象。
Block調用即是函數(shù)的調用。
#import "CLBlock.h"
@implementation CLBlock
- (void)blockTest {
int multiplier = 6;
int(^BlockTest)(int) = ^int(int num){
return num * multiplier;
};
BlockTest(2);
}
@end
clang(LLVM編譯器)具有轉換為我們可讀源代碼的功能。通過“-rewrite-objc”選項就能將含有Block語法的源代碼變換為C++的源代碼。說是C++,其實也僅是使用了struct結構,其本質是C語言源代碼。
使用【clang -rewrite-objc CLBlock.m】進行源碼解析,查看編譯后的文件內容。
// @implementation CLBlock
//Block結構體
struct __CLBlock__blockTest_block_impl_0 {
struct __block_impl impl;
struct __CLBlock__blockTest_block_desc_0* Desc;
int multiplier;
//構造函數(shù)
__CLBlock__blockTest_block_impl_0(void *fp, struct __CLBlock__blockTest_block_desc_0 *desc, int _multiplier, int flags=0) : multiplier(_multiplier) {
impl.isa = &_NSConcreteStackBlock;//isa指針,Block是對象的標志
impl.Flags = flags;
impl.FuncPtr = fp;//函數(shù)指針
Desc = desc;
}
};
/**函數(shù)
第一個參數(shù):Block結構體
第二個參數(shù):傳入?yún)?shù)
*/
static int __CLBlock__blockTest_block_func_0(struct __CLBlock__blockTest_block_impl_0 *__cself, int num) {
int multiplier = __cself->multiplier; // bound by copy
return num * multiplier;
}
static struct __CLBlock__blockTest_block_desc_0 {
size_t reserved;
size_t Block_size;
} __CLBlock__blockTest_block_desc_0_DATA = { 0, sizeof(struct __CLBlock__blockTest_block_impl_0)};
static void _I_CLBlock_blockTest(CLBlock * self, SEL _cmd) {
int multiplier = 6;
/*
int(^BlockTest)(int) = ^int(int num){
return num * multiplier;
};
*/
int(*BlockTest)(int) = ((int (*)(int))&__CLBlock__blockTest_block_impl_0((void *)__CLBlock__blockTest_block_func_0, &__CLBlock__blockTest_block_desc_0_DATA, multiplier));
/*
BlockTest(2);
*/
((int (*)(__block_impl *, int))((__block_impl *)BlockTest)->FuncPtr)((__block_impl *)BlockTest, 2);
}
// @end
struct __block_impl {
void *isa;//isa指針,Block是對象的標志
int Flags; //標志變量,在實現(xiàn)block的內部操作時會用到
int Reserved;//保留變量
void *FuncPtr;//函數(shù)指針
};
通過編譯后的源碼得知,block編譯后為一個含有isa指針的結構體,所以可以將block當做對象;而block的上下文內容被編譯后一個函數(shù)。而調用時便是將編譯后的上下文函數(shù)作為參數(shù)使用。
static struct __CLBlock__blockTest_block_desc_0 {
size_t reserved;//保留字段
size_t Block_size;//block大小(sizeof(struct __main_block_impl_0))
} __CLBlock__blockTest_block_desc_0_DATA = { 0, sizeof(struct __CLBlock__blockTest_block_impl_0)};
在定義__CLBlock__blockTest_block_desc_0結構體時,同時創(chuàng)建了__CLBlock__blockTest_block_desc_0_DATA,并給它賦值,以供在blockTest函數(shù)中對__CLBlock__blockTest_block_impl_0進行初始化。
截獲變量
為了保證 block 內部能夠正常訪問外部的變量,block 有一個變量捕獲機制。
- 對于基本數(shù)據(jù)類型的局部變量截獲其值。
- 對于對象類型的局部變量連同所有權修飾符一起截獲。
- 以指針形式截獲局部靜態(tài)變量。
- 不截獲全局變量、靜態(tài)全局變量
#import "CLBlock.h"
#import "Test.h"
@implementation CLBlock
int global_var = 4;//全局變量
static int static_global_var = 5;//靜態(tài)全局變量
- (void)blockTest {
//基本數(shù)據(jù)類型的局部變量
int var = 6;
//對象類型的局部變量
__unsafe_unretained id unsafe_objc = nil;
__strong id strong_obj = nil;
Test *test = nil;
//靜態(tài)局部變量
static int static_var = 7;
void(^BlockTest)(void) = ^{
NSLog(@"global_var==%d",global_var);
NSLog(@"static_global_var==%d",static_global_var);
NSLog(@"var==%d",var);
NSLog(@"unsafe_objc==%@",unsafe_objc);
NSLog(@"strong_obj==%@",strong_obj);
NSLog(@"test==%@",test);
NSLog(@"static_var==%d",static_var);
};
global_var = 41;
static_global_var = 51;
var = 61;
unsafe_objc = [[NSObject alloc] init];
strong_obj = [[NSObject alloc] init];
test = [[Test alloc] init];
static_var = 71;
BlockTest();
}
@end
運行結果
global_var==41
static_global_var==51
var==6
unsafe_objc==(null)
strong_obj==(null)
test==(null)
static_var==71
使用【clang -rewrite-objc -fobjc-arc CLBlock.m】命令進行源碼解析
int global_var = 4;
static int static_global_var = 5;
struct __CLBlock__blockTest_block_impl_0 {
struct __block_impl impl;
struct __CLBlock__blockTest_block_desc_0* Desc;
//截獲基本數(shù)據(jù)類型的局部變量的值
int var;
//對象類型的局部變量,其值連同所有權修飾符一起截獲
__unsafe_unretained id unsafe_objc;
__strong id strong_obj;
Test *__strong test;
//以指針形式截獲靜態(tài)局部變量
int *static_var;
//對全局變量、靜態(tài)全局變量不截獲
__CLBlock__blockTest_block_impl_0(void *fp, struct __CLBlock__blockTest_block_desc_0 *desc, int _var, __unsafe_unretained id _unsafe_objc, __strong id _strong_obj, Test *__strong _test, int *_static_var, int flags=0) : var(_var), unsafe_objc(_unsafe_objc), strong_obj(_strong_obj), test(_test), static_var(_static_var) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __CLBlock__blockTest_block_func_0(struct __CLBlock__blockTest_block_impl_0 *__cself) {
int var = __cself->var; // bound by copy
id unsafe_objc = __cself->unsafe_objc; // bound by copy
id strong_obj = __cself->strong_obj; // bound by copy
Test *test = __cself->test; // bound by copy
int *static_var = __cself->static_var; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_0,global_var);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_1,static_global_var);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_2,var);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_3,unsafe_objc);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_4,strong_obj);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_5,test);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_by_brpygpw16r5cz_vx4d7_prcw0000gn_T_CLBlock_a61b60_mi_6,(*static_var));
}
static void __CLBlock__blockTest_block_copy_0(struct __CLBlock__blockTest_block_impl_0*dst, struct __CLBlock__blockTest_block_impl_0*src) {_Block_object_assign((void*)&dst->unsafe_objc, (void*)src->unsafe_objc, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->strong_obj, (void*)src->strong_obj, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_assign((void*)&dst->test, (void*)src->test, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static void __CLBlock__blockTest_block_dispose_0(struct __CLBlock__blockTest_block_impl_0*src) {_Block_object_dispose((void*)src->unsafe_objc, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->strong_obj, 3/*BLOCK_FIELD_IS_OBJECT*/);_Block_object_dispose((void*)src->test, 3/*BLOCK_FIELD_IS_OBJECT*/);}
static struct __CLBlock__blockTest_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __CLBlock__blockTest_block_impl_0*, struct __CLBlock__blockTest_block_impl_0*);
void (*dispose)(struct __CLBlock__blockTest_block_impl_0*);
} __CLBlock__blockTest_block_desc_0_DATA = { 0, sizeof(struct __CLBlock__blockTest_block_impl_0), __CLBlock__blockTest_block_copy_0, __CLBlock__blockTest_block_dispose_0};
static void _I_CLBlock_blockTest(CLBlock * self, SEL _cmd) {
int var = 6;
__attribute__((objc_ownership(none))) id unsafe_objc = __null;
__attribute__((objc_ownership(strong))) id strong_obj = __null;
Test *test = __null;
static int static_var = 7;
void(*BlockTest)(void) = ((void (*)())&__CLBlock__blockTest_block_impl_0((void *)__CLBlock__blockTest_block_func_0, &__CLBlock__blockTest_block_desc_0_DATA, var, unsafe_objc, strong_obj, test, &static_var, 570425344));
global_var = 41;
static_global_var = 51;
var = 61;
unsafe_objc = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
strong_obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
test = ((Test *(*)(id, SEL))(void *)objc_msgSend)((id)((Test *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Test"), sel_registerName("alloc")), sel_registerName("init"));
static_var = 71;
((void (*)(__block_impl *))((__block_impl *)BlockTest)->FuncPtr)((__block_impl *)BlockTest);
}
__block修飾符
對被截獲的局部變量進行賦值操作需要__block修飾符;
對于靜態(tài)局部變量、全局變量、靜態(tài)全局變量不需要__block修飾符;
賦值≠使用
NSMutableArray *mArray = [[NSMutableArray alloc] init];
void(^Block)(void) = ^{
[mArray addObject:@123];
};
Block();
此種情況不需要__block修飾符。
__block原理
__block修飾的變量變成了對象。
示例:
#import "CLBlock.h"
#import "Test.h"
@implementation CLBlock
int global_var = 4;//全局變量
static int static_global_var = 5;//靜態(tài)全局變量
- (void)blockTest {
//基本數(shù)據(jù)類型的局部變量
__block int var = 6;
//對象類型的局部變量
__block __unsafe_unretained id unsafe_objc = nil;
__block __strong id strong_obj = nil;
__block Test *test = nil;
//靜態(tài)局部變量
static int static_var = 7;
void(^BlockTest)(void) = ^{
NSLog(@"global_var==%d",global_var);
NSLog(@"static_global_var==%d",static_global_var);
NSLog(@"var==%d",var);
NSLog(@"unsafe_objc==%@",unsafe_objc);
NSLog(@"strong_obj==%@",strong_obj);
NSLog(@"test==%@",test);
NSLog(@"static_var==%d",static_var);
};
global_var = 41;
static_global_var = 51;
var = 61;
unsafe_objc = [[NSObject alloc] init];
strong_obj = [[NSObject alloc] init];
test = [[Test alloc] init];
static_var = 71;
BlockTest();
NSMutableArray *mArray = [[NSMutableArray alloc] init];
void(^Block)(void) = ^{
[mArray addObject:@123];
};
Block();
}
@end
運行結果:
global_var==41
static_global_var==51
var==61
unsafe_objc==<NSObject: 0x600003ddc940>
strong_obj==<NSObject: 0x600003ddc940>
test==<Test: 0x600003ddc970>
static_var==71
查看源碼編譯:
int global_var = 4;
static int static_global_var = 5;
struct __Block_byref_var_0 {
void *__isa;
__Block_byref_var_0 *__forwarding;
int __flags;
int __size;
int var;
};
struct __Block_byref_unsafe_objc_1 {
void *__isa;
__Block_byref_unsafe_objc_1 *__forwarding;
int __flags;
int __size;
__unsafe_unretained id unsafe_objc;
};
struct __Block_byref_strong_obj_2 {
void *__isa;
__Block_byref_strong_obj_2 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
__strong id strong_obj;
};
struct __Block_byref_test_3 {
void *__isa;
__Block_byref_test_3 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
Test *__strong test;
};
struct __CLBlock__blockTest_block_impl_0 {
struct __block_impl impl;
struct __CLBlock__blockTest_block_desc_0* Desc;
int *static_var;
__Block_byref_var_0 *var; // by ref
__Block_byref_unsafe_objc_1 *unsafe_objc; // by ref
__Block_byref_strong_obj_2 *strong_obj; // by ref
__Block_byref_test_3 *test; // by ref
__CLBlock__blockTest_block_impl_0(void *fp, struct __CLBlock__blockTest_block_desc_0 *desc, int *_static_var, __Block_byref_var_0 *_var, __Block_byref_unsafe_objc_1 *_unsafe_objc, __Block_byref_strong_obj_2 *_strong_obj, __Block_byref_test_3 *_test, int flags=0) : static_var(_static_var), var(_var->__forwarding), unsafe_objc(_unsafe_objc->__forwarding), strong_obj(_strong_obj->__forwarding), test(_test->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
......
此處省略部分代碼
......
static void _I_CLBlock_blockTest(CLBlock * self, SEL _cmd) {
__attribute__((__blocks__(byref))) __Block_byref_var_0 var = {(void*)0,(__Block_byref_var_0 *)&var, 0, sizeof(__Block_byref_var_0), 6};
__attribute__((__blocks__(byref))) __attribute__((objc_ownership(none))) __Block_byref_unsafe_objc_1 unsafe_objc = {(void*)0,(__Block_byref_unsafe_objc_1 *)&unsafe_objc, 0, sizeof(__Block_byref_unsafe_objc_1), __null};
__attribute__((__blocks__(byref))) __attribute__((objc_ownership(strong))) __Block_byref_strong_obj_2 strong_obj = {(void*)0,(__Block_byref_strong_obj_2 *)&strong_obj, 33554432, sizeof(__Block_byref_strong_obj_2), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, __null};
__attribute__((__blocks__(byref))) __Block_byref_test_3 test = {(void*)0,(__Block_byref_test_3 *)&test, 33554432, sizeof(__Block_byref_test_3), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, __null};
static int static_var = 7;
void(*BlockTest)(void) = ((void (*)())&__CLBlock__blockTest_block_impl_0((void *)__CLBlock__blockTest_block_func_0, &__CLBlock__blockTest_block_desc_0_DATA, &static_var, (__Block_byref_var_0 *)&var, (__Block_byref_unsafe_objc_1 *)&unsafe_objc, (__Block_byref_strong_obj_2 *)&strong_obj, (__Block_byref_test_3 *)&test, 570425344));
global_var = 41;
static_global_var = 51;
(var.__forwarding->var) = 61;
(unsafe_objc.__forwarding->unsafe_objc) = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
(strong_obj.__forwarding->strong_obj) = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
(test.__forwarding->test) = ((Test *(*)(id, SEL))(void *)objc_msgSend)((id)((Test *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Test"), sel_registerName("alloc")), sel_registerName("init"));
static_var = 71;
((void (*)(__block_impl *))((__block_impl *)BlockTest)->FuncPtr)((__block_impl *)BlockTest);
NSMutableArray *mArray = ((NSMutableArray *(*)(id, SEL))(void *)objc_msgSend)((id)((NSMutableArray *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSMutableArray"), sel_registerName("alloc")), sel_registerName("init"));
void(*Block)(void) = ((void (*)())&__CLBlock__blockTest_block_impl_1((void *)__CLBlock__blockTest_block_func_1, &__CLBlock__blockTest_block_desc_1_DATA, mArray, 570425344));
((void (*)(__block_impl *))((__block_impl *)Block)->FuncPtr)((__block_impl *)Block);
}
以基本數(shù)據(jù)類型為例,通過與添加__block修飾符之前源碼對比發(fā)現(xiàn):
int類型變?yōu)?code>__Block_byref_var_0*對象類型;
賦值時由var = 61;變?yōu)?code>(var.__forwarding->var) = 61;

Block的內存管理
根據(jù)Block在內存中的位置分為三種類型:
- 全局類型:_NSConcreteGlobalBlock,位于全局區(qū)的block,它是設置在程序的數(shù)據(jù)區(qū)域(.data區(qū))中。
- 棧類型:_NSConcreteStackBlock,位于棧區(qū),超出變量作用域,棧上的Block以及 __block變量都被銷毀。
- 堆類型:_NSConcreteMallocBlock位于堆區(qū),在變量作用域結束時不受影響。
_NSConcreteGlobalBlock
生成全局類型Block有兩種情況
- 定義全局變量的地方有Block語法時
#import "CLBlock.h"
@implementation CLBlock
void(^BlockTest)(void) = ^{ };
- (void)blockTest {
}
@end
編譯后
struct __BlockTest_block_impl_0 {
struct __block_impl impl;
struct __BlockTest_block_desc_0* Desc;
__BlockTest_block_impl_0(void *fp, struct __BlockTest_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteGlobalBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
- Block語法不使用截獲的自動變量時候
int (^BlockTest)(int num) = ^(int num){
return num;
};
BlockTest(2);
雖然,這個Block在循環(huán)內,但是Block的地址總是不變的。說明這個Block在全局段。注:針對沒有捕獲自動變量的Block來說,雖然用clang的rewrite-objc轉化后的代碼中仍顯示_NSConcretStackBlock,但是實際上不是這樣的。????
_NSConcreteStackBlock
設置在棧上的Block,如果其作用域結束,該Block就被銷毀。同樣的,由于__block變量也配置在棧上,如果其作用域結束,則該__block變量也會被銷毀。
_NSConcreteMallocBlock
堆類型Block無法直接創(chuàng)建,需要由_NSConcreteStackBlock類型的block拷貝而來(也就是說block需要執(zhí)行copy之后才能存放到堆中)。
- 棧Block被拷貝生成到堆情況
1.調用Block的copy實例方法時
2.Block作為函數(shù)返回值返回時
3.將Block賦值給附有__strong修飾符id類型的類或Block類型成員變量時
4.將方法名中含有usingBlock的Cocoa框架方法或GCD的API中傳遞Block時
Block的copy操作

Block由棧 copy至堆的內存使用變化
-
當棧上的Block被復制到堆上時,__block變量也會隨之復制,并且Block持有該變量
單個Block使用__block變量.png -
多個Block中使用__block變量時,任何一個Block被復制到堆時,__block變量也會一并復制到堆并被持有,其余Block被復制時,僅需要__block 變量的引用計數(shù)
多個Block中使用__block變量.png
和使用引用計數(shù)一樣,在堆上的Block被廢棄,它所引用的__block變量將被釋放

理解Block作用域之后,我們發(fā)現(xiàn)這和OC引用計數(shù)方式管理方式一樣,使用__block修飾符來持有對象,當Block被廢棄之后,__block修飾變量也隨之釋放
當Block被復制到堆之后,會將自身的__forwarding指針更新,依然指向“最新”的自己,這樣就保證了在棧上或者堆上都能正確訪問對應變量

__forwarding無論在任何內存位置,都可以順利的訪問同一個__block變量。
Block的循環(huán)引用
循環(huán)引用
當前對象持有block,在block中使用self又造成block持有self,引起循環(huán)引用。
- (void)blockTest {
_block = ^{
NSLog(@"%@",self.test);
};
}
使用__weak關鍵字解除循環(huán)引用:
- (void)blockTest {
__weak typeof(self)weakSelf = self;
_block = ^{
NSLog(@"%@",weakSelf.test);
};
}
__block引起的循環(huán)引用
注意:
MRC 下,__block修改對象不會引起其引用計數(shù),避免了循環(huán)引用。
ARC下,__block修改對象會引起強引用,無法避免了循環(huán)引用,需要手動解環(huán)。
- (void)blockTest {
__block CLBlock *blockSelf = self;
_block = ^{
NSLog(@"%@",blockSelf.test);
};
_block();
}
對象持有Block,Block持有__block變量,__block變量持有對象,引起大環(huán)引用。
解決方式:
- (void)blockTest {
__block CLBlock *blockSelf = self;
_block = ^{
NSLog(@"%@",blockSelf.test);
blockSelf = nil;
};
_block();
}
注意:如果Block一直不調用,無法解環(huán)。
Block對對象的長引用
Block 中如果持有了self就會對其強引用,項目中有許多地方在Block中持有self并不會引起循環(huán)引用(如在封裝的網(wǎng)絡請求中),但是可能持有較長的時間,建議此時使用__weak進行弱引用處理。
__weak typeof(self)weakSelf = self;
[[NetworkRequest sharedInstance] request:@{}
successBlock:^(id _Nullable responseObject) {
weakSelf.responseObject = responseObject;
} errorBlock:^(NSError *error) {
} failureBlock:^(NSError *error) {
}];
__strong使用
如果網(wǎng)絡異步返回Block,Block執(zhí)行的過程中頁面返回,由于__weak對對象進行弱引用,則此時對象會被釋放,異步運行中的對象變成nil,引起異常。
示例:
__weak typeof(self)weakSelf = self;
[[NetworkRequest sharedInstance] request:@{} successBlock:^(id _Nullable responseObject) {
NSLog(@"weakSelf對象地址:%@",weakSelf);
for (int i = 0; i < 10000; i++) {
NSLog(@"%d",i);
}
NSLog(@"耗時的任務 結束 weakSelf對象地址:%@",weakSelf);
} errorBlock:^(NSError * _Nonnull error) {
} failureBlock:^(NSError * _Nonnull error) {
}];
打印結果
weakSelf對象地址:<AViewController: 0x7fc2ffd06c10>
...
省略
...
耗時的任務 結束 weakSelf對象地址:(null)
此時需要在Block中使用__strong修飾符,在Block開始執(zhí)行時,檢驗弱引用的對象是否還存在,如果存在,使用__strong進行強引用,此時引用計數(shù)加1,這樣在Block執(zhí)行的過程中,這個對象就不會被置為nil,而在Block執(zhí)行完畢后,對象的引用計數(shù)就會減1,這樣就不會導致對象無法釋放。
__weak typeof(self)weakSelf = self;
[[NetworkRequest sharedInstance] request:@{} successBlock:^(id _Nullable responseObject) {
if (!weakSelf) return;
__strong typeof(weakSelf)strongSelf = weakSelf;
NSLog(@"strongSelf對象地址:%@",strongSelf);
for (int i = 0; i < 10000; i++) {
// 模擬一個耗時的任務
NSLog(@"%d",i);
}
NSLog(@"耗時的任務 結束 strongSelf對象地址:%@",strongSelf);
} errorBlock:^(NSError * _Nonnull error) {
} failureBlock:^(NSError * _Nonnull error) {
}];
運行結果:
strongSelf對象地址:<AViewController: 0x7f9f5371ee60>
...
省略
...
耗時的任務 結束 strongSelf對象地址:<AViewController: 0x7f9f5371ee60>
區(qū)別:
直接使用self,會在編譯時強引用self,引起循環(huán)引用;
使用__weak后再在Block中使用__strong,則只會在運行到Block中時才會強引用,引用計數(shù)進行加1操作,Block執(zhí)行完畢后引用計數(shù)減1。
- 參考及內容引用資料
iOS中Block的用法,舉例,解析與底層原理(這可能是最詳細的Block解析)
(四)Block之 __block修飾符及其存儲域
iOS中Block實現(xiàn)原理的全面分析
__weak和__strong在Block中的使用
Block的本質與使用

