什么是Block(快速實(shí)現(xiàn)直接輸入inlink)
Block是一種特殊的數(shù)據(jù)類型
Block的作用
- 用于保存一段代碼,可以在恰當(dāng)?shù)臅r(shí)間取出來(lái)調(diào)用
- 功能類似于函數(shù)和方法
Block的格式
返回值(^block變量名)(形參列表) = ^( 形參列表){
}捂刺;
-
無(wú)參數(shù)無(wú)返回值
void (^sunBlock)(); sunBlock = ^{ NSLog(@"sunBlock"); }; sunBlock();
-
有參數(shù)無(wú)返回值
void(^sunBlock)(int,int); sunBlock = ^(int value1,int value2){ NSLog(@"%d",value1 + value2); }; sunBlock(10,20);
-
有參數(shù)有返回值
int (^sunBlock)(int,int); sunBlock = ^(int value1,int value2){ return value1 + value2; }; NSLog(@"%d",sunBlock(10,20));
typedef 和Block
利用typedef給block起別名,和指向函數(shù)的指針一樣婴削,block變量的名稱就是別名
typedef int (^calculateBlock)(int,int);
int main(int argc, const char * argv[]) {
calculateBlock sumBlock = ^(int value1,int value2){
return value1 + value2;
};
NSLog(@"%d",sumBlock(20,10));
calculateBlock minusBlock = ^(int value1,int value2){
return value1 - value2;
};
NSLog(@"%d",minusBlock(20,10));
}
Block的底層實(shí)現(xiàn)
- 原文件:
int main(int argc, const char * argv[]) {
^{ };
return 0;
}
- 通過(guò)clang命令將OC轉(zhuǎn)為C++代碼來(lái)查看一下Block底層實(shí)現(xiàn),clang命令使用方式為終端使用cd定位到main.m文件所在文件夾,然后利用clang -rewrite-objc main.m將OC轉(zhuǎn)為C++,成功后在main.m同目錄下會(huì)生成一個(gè)main.cpp文件
struct __block_impl {
void *isa; //isa晦炊,指向所屬類的指針璧瞬,也就是block的類型
int Flags; //flags,標(biāo)志變量麻裁,在實(shí)現(xiàn)block的內(nèi)部操作時(shí)會(huì)用到
int Reserved; //Reserved箍镜,保留變量
void *FuncPtr; //block執(zhí)行時(shí)調(diào)用的函數(shù)指針
};
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; //__main_block_impl_0的isa指針指向了_NSConcreteStackBlock
impl.Flags = flags;
impl.FuncPtr = fp; //從main函數(shù)中看, __main_block_impl_0的FuncPtr指向了函數(shù)__main_block_func_0
Desc = desc; //__main_block_impl_0的Desc也指向了定義__main_block_desc_0時(shí)就創(chuàng)建的__main_block_desc_0_DATA煎源,其中紀(jì)錄了block結(jié)構(gòu)體大小等信息色迂。
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
}
static struct __main_block_desc_0 {
size_t reserved; //保留字段
size_t Block_size; //block大小(sizeof(struct __main_block_impl_0))
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
//以上代碼在定義__main_block_desc_0結(jié)構(gòu)體時(shí),同時(shí)創(chuàng)建了__main_block_desc_0_DATA手销,并給它賦值歇僧,以供在main函數(shù)中對(duì)__main_block_impl_0進(jìn)行初始化。
int main(int argc, const char * argv[]) {
((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
return 0;
}
1锋拖、__block_impl結(jié)構(gòu)體诈悍,它包含了isa指針(包含isa指針的皆為對(duì)象),也就是說(shuō)block也是一個(gè)對(duì)象
2兽埃、__main_block_impl_0結(jié)構(gòu)體侥钳,可以看出是根據(jù)所在函數(shù)(main函數(shù))以及出現(xiàn)序列(第0個(gè))進(jìn)行命名的,如果是全局的blcok柄错,就根據(jù)變量名和出現(xiàn)序列進(jìn)行命名舷夺。
3苦酱、__main_block_impl_0中包含了倆個(gè)成員變量和一個(gè)構(gòu)造函數(shù),成員變量分別是__block_impl結(jié)構(gòu)體和描述信息Desc给猾,之后在構(gòu)造函數(shù)中初始化block的類型信息和函數(shù)指針等信息疫萤。
4、__main_block_func_0函數(shù)敢伸,其實(shí)對(duì)應(yīng)的block的函數(shù)體扯饶,該函數(shù)接受了一個(gè)__cself參數(shù),其實(shí)就是對(duì)應(yīng)的block本身
5详拙、__main_block_desc_0結(jié)構(gòu)體帝际,其中比較有價(jià)值的信息是block的大小
6蔓同、main函數(shù)對(duì)block的創(chuàng)建饶辙,可以看出執(zhí)行block就是調(diào)用一個(gè)以block自身為參數(shù)的函數(shù),這個(gè)函數(shù)對(duì)應(yīng)著block的執(zhí)行體斑粱。
Block的分類
- NSConcreteGlobalBlock 全局的靜態(tài) block弃揽,不會(huì)訪問(wèn)任何外部變量。
- NSConcreteStackBlock 保存在棧中的 block则北,當(dāng)函數(shù)返回時(shí)會(huì)被銷毀矿微。
- NSConcreteMallocBlock 保存在堆中的 block,當(dāng)引用計(jì)數(shù)為 0 時(shí)會(huì)被銷毀尚揣。
NSConcreteGlobalBlock 類型的 block 的實(shí)現(xiàn)
void (^testGlobalBlock)() = ^{
NSLog(@"hello block");
};
int main(int argc, const char * argv[]) {
testGlobalBlock();
return 0;
}
testGlobalBlock的isa指向了_NSConcreteGlobalBlock涌矢,即在全局區(qū)域創(chuàng)建,block變量存儲(chǔ)在全局?jǐn)?shù)據(jù)存儲(chǔ)區(qū)
NSConcreteStackBlock 類型的 block 的實(shí)現(xiàn)
int main(int argc, const char * argv[]) {
void (^testStackBlock)() = ^{
NSLog(@"hello block");
};
testStackBlock();
return 0;
}
testStackBlock的isa指向了_NSConcreteStackBlock快骗,即在棧區(qū)創(chuàng)建娜庇。
NSConcreteMallocBlock 類型的 block 的實(shí)現(xiàn)
int main(int argc, const char * argv[]) {
void (^testStackBlock)() = [^{
NSLog(@"hello block");
} copy];
testStackBlock();
return 0;
}
NSConcreteMallocBlock 類型的 block 通常不會(huì)在源碼中直接出現(xiàn),其需要由_NSConcreteStackBlock類型的block拷貝而來(lái)(也就是說(shuō)block需要執(zhí)行copy之后才能存放到堆中)方篮。
其內(nèi)部通過(guò)函數(shù)memmove將棧中的block的內(nèi)容拷貝到了堆中名秀,并使isa指向了_NSConcreteMallocBlock。
block主要的一些學(xué)問(wèn)就出在棧中block向堆中block的轉(zhuǎn)移過(guò)程中了藕溅。
Block的應(yīng)用
Block中訪問(wèn)局部變量
- 在Block中訪問(wèn)局部變量
int main(int argc, const char * argv[]) {
int testNum = 10;
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
打印結(jié)果:10
- 在聲明Block之后匕得,調(diào)用Block之前對(duì)局部變量進(jìn)行修改,在調(diào)用Block時(shí)局部變量值是修改之前的舊值
int main(int argc, const char * argv[]) {
int testNum = 10;
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNum = 20;
testNumBlock();
return 0;
}
打印結(jié)果:10
- 在Block中不可以直接修改局部變量
int main(int argc, const char * argv[]) {
int testNum = 10;
void(^testNumBlock)() = ^{
testNum = 20; //報(bào)錯(cuò)
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
Block內(nèi)訪問(wèn)__block修飾的局部變量
- 在局部變量前使用下劃線下劃線block修飾,在聲明Block之后巾表、調(diào)用Block之前對(duì)局部變量進(jìn)行修改,在調(diào)用Block時(shí)局部變量值是修改之后的新值
__block int testNum = 10;
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNum = 20;
testNumBlock();
打印結(jié)果:20
- 在局部變量前使用下劃線下劃線block修飾,在Block中可以直接修改局部變量
int main(int argc, const char * argv[]) {
__block int testNum = 10;
void(^testNumBlock)() = ^{
testNum = 20;
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
打印結(jié)果:20
Block內(nèi)訪問(wèn)全局變量
- 在Block中可以訪問(wèn)全局變量
int testNum = 10;
int main(int argc, const char * argv[]) {
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
打印結(jié)果:10
- 在聲明Block之后汁掠、調(diào)用Block之前對(duì)全局變量進(jìn)行修改,在調(diào)用Block時(shí)全局變量值是修改之后的新值
int testNum = 10;
int main(int argc, const char * argv[]) {
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNum = 20;
testNumBlock();
return 0;
}
打印結(jié)果:20
- 在Block中可以直接修改全局變量
int testNum = 10;
int main(int argc, const char * argv[]) {
void(^testNumBlock)() = ^{
testNum = 20;
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
打印結(jié)果:20
Block內(nèi)訪問(wèn)靜態(tài)變量
- 在Block中可以訪問(wèn)靜態(tài)變量
int main(int argc, const char * argv[]) {
static int testNum = 10;
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
打印結(jié)果:10
- 在聲明Block之后、調(diào)用Block之前對(duì)靜態(tài)變量進(jìn)行修改,在調(diào)用Block時(shí)靜態(tài)變量值是修改之后的新值
int main(int argc, const char * argv[]) {
static int testNum = 10;
void(^testNumBlock)() = ^{
NSLog(@"%d",testNum);
};
testNum = 20;
testNumBlock();
return 0;
}
打印結(jié)果:20
- 在Block中可以直接修改靜態(tài)變量
int main(int argc, const char * argv[]) {
static int testNum = 10;
void(^testNumBlock)() = ^{
testNum = 20;
NSLog(@"%d",testNum);
};
testNumBlock();
return 0;
}
打印結(jié)果:20
Block作為參數(shù)傳遞
typedef void(^TestBlock)();
NSMutableArray *array;
void test(){
int a = 10;
TestBlock blcok = ^{
NSLog(@"%d",a);
};
[array addObject:blcok];
NSLog(@"%@",blcok);
}
int main(int argc, const char * argv[]) {
array = [[NSMutableArray alloc]init];
test();
TestBlock blockk = [array lastObject];
blockk();
NSLog(@"%@",blockk);
return 0;
}
結(jié)果:
在ARC下:
test2[2423:124143] <__NSMallocBlock__: 0x1004037f0>
test2[2423:124143] 10
test2[2423:124143] <__NSMallocBlock__: 0x1004037f0>
在非ARC下:
程序崩潰
test2[2449:125851] <__NSStackBlock__: 0x7fff5fbff6f8>
1集币、在非ARC下考阱,TestBlock的isa指向NSStackBlock,當(dāng)函數(shù)退出后惠猿,相應(yīng)的堆被銷毀羔砾,block也就不存在了负间,在經(jīng)過(guò)copy或retain之后,對(duì)象的類型從NSStackBlock變?yōu)榱?strong>NSMallocBlock姜凄,在函數(shù)結(jié)束后依然可以訪問(wèn)政溃,在非ARC環(huán)境下,copy或retain了block后一定要在使用后release态秧,不然會(huì)有內(nèi)存泄露董虱,而且泄露點(diǎn)是在系統(tǒng)級(jí),在Instruments里跟不到問(wèn)題觸發(fā)點(diǎn)申鱼,比較上火愤诱。
2、ARC情況下,系統(tǒng)會(huì)將捕獲了外部變量的block進(jìn)行了copy捐友。所以返回類型為NSMallocBlock淫半,在函數(shù)結(jié)束后依然可以訪問(wèn)
如果把blcok中的代碼不再訪問(wèn)變量:
TestBlock blcok = ^{
NSLog(@"demo");
};
結(jié)果:
ARC和非ARC得結(jié)果一致
test2[2484:128052] <__NSGlobalBlock__: 0x100005290>
test2[2484:128052] demo
test2[2484:128052] <__NSGlobalBlock__: 0x100005290>
Block作為返回值
- 非ARC中
- (testBlcok) myTestBlock {
__block int val = 10;
return ^{
NSLog(@"val = %d", val);
};
}
結(jié)果:Xcode就會(huì)提示報(bào)錯(cuò)Returning block that lives on the local stack
在向外傳遞block的時(shí)候一定也要做到,傳給外面一個(gè)在堆上的匣砖,autorelease的對(duì)象科吭。
- (testBlcok) myTestBlock {
__block int val = 10;
return [[^{
NSLog(@"val = %d", val);
} copy] autorelease];
}
- ARC中
- (testBlcok) myTestBlock {
__block int val = 10;
return ^{
NSLog(@"val = %d", val);
};
}
結(jié)果:正常
在ARC環(huán)境下,當(dāng)block作為參數(shù)返回的時(shí)候猴鲫,block也會(huì)自動(dòng)被移到堆上对人。
Block作為屬性
ARC 和非ARC得聲明一樣
@property (strong, nonatomic) TestBlock *strongBlock;
@property (copy, nonatomic) TestBlock *copyBlock;
Block在MRC及ARC下的內(nèi)存管理
Block在MRC下的內(nèi)存管理
- 默認(rèn)情況下,Block的內(nèi)存存儲(chǔ)在棧中,不需要開(kāi)發(fā)人員對(duì)其進(jìn)行內(nèi)存管理
- (void)viewDidLoad {
[super viewDidLoad];
void(^testBlock)() = ^{
NSLog(@"------");
};
testBlock();
}
結(jié)果:當(dāng)testBlock變量出了作用域,testBlock的內(nèi)存會(huì)被自動(dòng)釋放
- 在Block的內(nèi)存存儲(chǔ)在棧中時(shí),如果在Block中引用了外面的對(duì)象,不會(huì)對(duì)所引用的對(duì)象進(jìn)行任何操作
- (void)viewDidLoad {
[super viewDidLoad];
Student *stu = [[Student alloc]init];
void(^testBlock)() = ^{
NSLog(@"%@",stu);
};
testBlock();
[stu release];
}
結(jié)果:Student可以正常釋放
- 如果對(duì)Block進(jìn)行一次copy操作,那么Block的內(nèi)存會(huì)被移動(dòng)到堆中,這時(shí)需要對(duì)其進(jìn)行release操作來(lái)管理內(nèi)存
- (void)viewDidLoad {
[super viewDidLoad];
void(^testBlock)() = ^{
NSLog(@"testBlock");
};
testBlock();
Block_copy(testBlock);
Block_release(testBlock);
}
結(jié)果:Block正常釋放
- 如果對(duì)Block進(jìn)行一次copy操作,那么Block的內(nèi)存會(huì)被移動(dòng)到堆中,在Block的內(nèi)存存儲(chǔ)在堆中時(shí),如果在Block中引用了外面的對(duì)象,會(huì)對(duì)所引用的對(duì)象進(jìn)行一次retain操作,即使在Block自身調(diào)用了release操作之后,Block也不會(huì)對(duì)所引用的對(duì)象進(jìn)行一次release操作,這時(shí)會(huì)造成內(nèi)存泄漏
- (void)viewDidLoad {
[super viewDidLoad];
Student *stu = [[Student alloc]init];
void(^testBlock)() = ^{
NSLog(@"%@",stu);
};
testBlock();
Block_copy(testBlock);
Block_release(testBlock);
[stu release];
}
結(jié)果:Student無(wú)法正常被釋放,因?yàn)槠湓贐lock中被進(jìn)行了一次retain操作
- 如果對(duì)Block進(jìn)行一次copy操作,那么Block的內(nèi)存會(huì)被移動(dòng)到堆中,在Block的內(nèi)存存儲(chǔ)在堆中時(shí),如果在Block中引用了外面的對(duì)象,會(huì)對(duì)所引用的對(duì)象進(jìn)行一次retain操作,為了不對(duì)所引用的對(duì)象進(jìn)行一次retain操作,可以在對(duì)象的前面使用__block來(lái)修飾
- (void)viewDidLoad {
[super viewDidLoad];
__block Student *stu = [[Student alloc]init];
void(^testBlock)() = ^{
NSLog(@"%@",stu);
};
testBlock();
Block_copy(testBlock);
Block_release(testBlock);
[stu release];
}
結(jié)果:Student可以正常釋放
- 如果對(duì)象內(nèi)部有一個(gè)Block屬性,而在Block內(nèi)部又訪問(wèn)了該對(duì)象,那么會(huì)造成循環(huán)引用
- 第一種情況
@interface Student : NSObject
@property (nonatomic,copy) void(^testBlock)();
@end
----------------------------------------------
@implementation Student
-(void)dealloc{
NSLog(@"%s",__func__);
Block_release(_testBlock);
[super dealloc];
}
@end
----------------------------------------------
-(void)viewDidLoad {
[super viewDidLoad];
Student *stu = [[Student alloc]init];
stu.testBlock = ^{
NSLog(@"%@",stu);
};
stu.testBlock();
[stu release];
}
結(jié)果:因?yàn)閠estBlock作為Student的屬性,采用copy修飾符修飾(這樣才能保證Block在堆里面,以免Block在棧中被系統(tǒng)釋放),所以Block會(huì)對(duì)Student對(duì)象進(jìn)行一次retain操作,導(dǎo)致循環(huán)引用無(wú)法釋放
- 第二種情況
@interface Student : NSObject
@property (nonatomic,copy) void(^testBlock)();
-(void)resetBlock;
@end
----------------------------------------------
@implementation Student
-(void)resetBlock{
self.testBlock = ^{
NSLog(@"%@",self);
};
}
-(void)dealloc{
NSLog(@"%s",__func__);
Block_release(_testBlock);
[super dealloc];
}
@end
----------------------------------------------
-(void)viewDidLoad {
[super viewDidLoad];
Student *stu = [[Student alloc]init];
[stu resetBlock];
[stu release];
}
結(jié)果:Student對(duì)象在這里無(wú)法正常釋放,雖然表面看起來(lái)一個(gè)alloc對(duì)應(yīng)一個(gè)release符合內(nèi)存管理規(guī)則,但是實(shí)際在resetBlock方法實(shí)現(xiàn)中,Block內(nèi)部對(duì)self進(jìn)行了一次retain操作,導(dǎo)致循環(huán)引用無(wú)法釋放
- 如果對(duì)象內(nèi)部有一個(gè)Block屬性,而在Block內(nèi)部又訪問(wèn)了該對(duì)象,那么會(huì)造成循環(huán)引用,解決循環(huán)引用的辦法是在對(duì)象的前面使用下劃線下劃線block來(lái)修飾,以避免Block對(duì)對(duì)象進(jìn)行retain操作
- 第一種情況
@interface Student : NSObject @property (nonatomic,copy) void(^testBlock)(); @end ---------------------------------------------- @implementation Student -(void)dealloc{ NSLog(@"%s",__func__); Block_release(_testBlock); [super dealloc]; } @end ---------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; __block Student *stu = [[Student alloc]init]; stu.testBlock = ^{ NSLog(@"%@",stu); }; stu.testBlock(); [stu release]; } 結(jié)果:Student可以正常釋放
- 第二種情況
@interface Student : NSObject @property (nonatomic,copy) void(^testBlock)(); -(void)resetBlock; @end ---------------------------------------------- @implementation Student -(void)resetBlock{ // 這里為了通用一點(diǎn),可以使用__block typeof(self) stu = self; __block Student *stu = self; self.testBlock = ^{ NSLog(@"%@",stu); }; } -(void)dealloc{ NSLog(@"%s",__func__); Block_release(_testBlock); [super dealloc]; } @end ---------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; Student *stu = [[Student alloc]init]; [stu resetBlock]; [stu release]; } 結(jié)果:Student可以正常釋放
Block在ARC下的內(nèi)存管理
- 在ARC默認(rèn)情況下,Block的內(nèi)存存儲(chǔ)在堆中,ARC會(huì)自動(dòng)進(jìn)行內(nèi)存管理,程序員只需要避免循環(huán)引用即可
- (void)viewDidLoad {
[super viewDidLoad];
void(^testBlock)() = ^{
NSLog(@"testBlock");
};
testBlock();
}
結(jié)果:當(dāng)Block變量出了作用域,Block的內(nèi)存會(huì)被自動(dòng)釋放
- 在Block的內(nèi)存存儲(chǔ)在堆中時(shí),如果在Block中引用了外面的對(duì)象,會(huì)對(duì)所引用的對(duì)象進(jìn)行強(qiáng)引用,但是在Block被釋放時(shí)會(huì)自動(dòng)去掉對(duì)該對(duì)象的強(qiáng)引用,所以不會(huì)造成內(nèi)存泄漏
- (void)viewDidLoad {
[super viewDidLoad];
Student *stu = [[Student alloc]init];
void(^testBlock)() = ^{
NSLog(@"%@",stu);
};
testBlock();
}
結(jié)果:Student可以正常釋放
- 如果對(duì)象內(nèi)部有一個(gè)Block屬性,而在Block內(nèi)部又訪問(wèn)了該對(duì)象,那么會(huì)造成循環(huán)引用
- 第一種情況
@interface Student : NSObject @property (nonatomic,copy) void(^testBlock)(); @end ---------------------------------------------- @implementation Student -(void)dealloc{ NSLog(@"%s",__func__); } @end ---------------------------------------------- -(void)viewDidLoad { [super viewDidLoad]; Student *stu = [[Student alloc]init]; stu.testBlock = ^{ NSLog(@"%@",stu); }; stu.testBlock(); } 結(jié)果:因?yàn)閠estBlock作為Student的屬性,采用copy修飾符修飾(這樣才能保證Block在堆里面,以免Block在棧中被系統(tǒng)釋放),所以Block會(huì)對(duì)Person對(duì)象進(jìn)行一次強(qiáng)引用,導(dǎo)致循環(huán)引用無(wú)法釋放
- 第二種情況
@interface Student : NSObject @property (nonatomic,copy) void(^testBlock)(); - (void)resetBlock; @end ---------------------------------------------- @implementation Student - (void)resetBlock { self.testBlock = ^{ NSLog(@"------%@", self); }; } -(void)dealloc{ NSLog(@"%s",__func__); } @end ---------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; Student *stu = [[Student alloc]init]; [stu resetBlock]; } 結(jié)果:Student對(duì)象在這里無(wú)法正常釋放,在testBlock方法實(shí)現(xiàn)中,Block內(nèi)部對(duì)self進(jìn)行了一次強(qiáng)引用,導(dǎo)致循環(huán)引用無(wú)法釋放
- 如果對(duì)象內(nèi)部有一個(gè)Block屬性,而在Block內(nèi)部又訪問(wèn)了該對(duì)象,那么會(huì)造成循環(huán)引用,解決循環(huán)引用的辦法是使用一個(gè)弱引用的指針指向該對(duì)象,然后在Block內(nèi)部使用該弱引用指針來(lái)進(jìn)行操作,這樣避免了Block對(duì)對(duì)象進(jìn)行強(qiáng)引用
- 第一種情況
@interface Student : NSObject
@property (nonatomic,copy) void(^testBlock)();
@end
----------------------------------------------
@implementation Student
-(void)dealloc{
NSLog(@"%s",__func__);
}
@end
----------------------------------------------
- (void)viewDidLoad {
[super viewDidLoad];
Student *stu = [[Student alloc]init];
__weak typeof(stu) weakS = stu;
stu.testBlock = ^{
NSLog(@"------%@", weakS);
};
stu.testBlock();
// Student對(duì)象在這里可以正常被釋放
}
- 第二種情況
@interface Student : NSObject @property (nonatomic,copy) void(^testBlock)(); -(void)resetBlock; @end ---------------------------------------------- @implementation Student -(void)resetBlock { //這里為了通用一點(diǎn),可以使用__weak typeof(self) weakP = self; __weak Student *stu = self; self.testBlock = ^{ NSLog(@"------%@", self); }; } -(void)dealloc{ NSLog(@"%s",__func__); } @end ---------------------------------------------- -(void)viewDidLoad { [super viewDidLoad]; Student *stu = [[Student alloc]init]; [stu resetBlock]; } 結(jié)果:Student可以正常釋放
注: 關(guān)于下劃線下劃線block關(guān)鍵字在MRC和ARC下的不同
__block在MRC下有兩個(gè)作用
- 允許在Block中訪問(wèn)和修改局部變量
- 禁止Block對(duì)所引用的對(duì)象進(jìn)行隱式retain操作
__block在ARC下只有一個(gè)作用
- 允許在Block中訪問(wèn)和修改局部變量