一 概述
閉包就是1個(gè)函數(shù)或指向函數(shù)的指針+該函數(shù)的執(zhí)行的上下文變量(也就是自由變量),Block是OC對(duì)于閉包的實(shí)現(xiàn)。其中Block可以定義在方法的內(nèi)部或外部,其本質(zhì)是對(duì)象,作用是使代碼高聚合,只有調(diào)用Block的時(shí)候,才會(huì)調(diào)用代碼塊里的內(nèi)容。
使用clang將OC代碼轉(zhuǎn)換為C++文件查看block的方法:
- 在命令行輸入代碼 clang -rewrite-objc 需要編譯的OC的.m文件(如果這步報(bào)錯(cuò)找不到UIKit,就是用這個(gè)命令生成 clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk 需要編譯的OC的.m)
- 這時(shí)查看當(dāng)前的文件夾里 多了一個(gè)相同名稱的 .cpp文件,可以在命令行輸入 open 生成的.cpp 查看文件
開發(fā)中常用typedef定義一個(gè)block
void(^myBlock)(void);
使用時(shí)直接
@property (nonatomic, copy) myBlock blk;
self.blk = ^(){
NSLog(@"typedef定義的block");
};
定義一個(gè)無參數(shù)無返回值的block
void(^myBlock1)(void) = ^(){
NSLog(@"我是無參無返回值block");
};
定義一個(gè)有參數(shù)無返回值的block
void(^myBlock2)(NSString* string) = ^(NSString* string) {
NSLog(@"我是有參數(shù)無返回值block");
};
定義一個(gè)有參數(shù)有返回值的block
NSString*(^myBlock3)(NSString* string) = ^(NSString* string){
return [string stringByAppendingString:@"我是有參數(shù)有返回值的block"];
};
二 Block與外部變量
截取局部變量的值
- 默認(rèn)情況下,對(duì)于block外的變量引用,block是將其值復(fù)制到block內(nèi)部的結(jié)構(gòu)體中來訪問的,也就是說block的自動(dòng)變量的截取只針對(duì)block塊內(nèi)部使用的自動(dòng)變量,不使用則不截取。特別注意默認(rèn)情況下block只能訪問不能修改局部變量的值。
int a = 10;
void(^myBlock)(void) = ^{
NSLog(@"a的值是%d",a);
};
a = 20;
myBlock();
輸出結(jié)果為a=10,因?yàn)樵赼 = 20賦值之前,a=10的值被截取到了block內(nèi)部,a不管外部怎么變化,block內(nèi)部的a永遠(yuǎn)都為10。
使用__block修飾的外部變量
對(duì)于用__block修飾的外部變量的引用,block是復(fù)制其引用地址來實(shí)現(xiàn)訪問的,所以block內(nèi)部可以修改__block修飾的外部變量的值。
__block int a = 10;
void(^myBlock)(void) = ^{
NSLog(@"a的值是%d",a);
};
a = 20;
myBlock();
輸出結(jié)果為a=20
為什么__block修飾的外部變量的值就可以在block內(nèi)部修改呢?
我們使用clang 將這個(gè).m文件轉(zhuǎn)成 .cpp查看一下
__attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 10};
void(*myBlock)(void) = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
(a.__forwarding->a) = 20;
發(fā)現(xiàn)局部變量a變成了__Block_byref_a_0結(jié)構(gòu)體類型的自動(dòng)變量實(shí)例