定义块的语法格式:
^ [块返回值类型] (形参类型1 形参1, 形参类型2 形参2, ...){
//块执行体
}
定义块的语法与定义函数的语法存在如下差异:
若需多次调用已经定义的块,可定义一个块变量,将该块赋给块变量,通过块变量来调用块。定义块变量的格式:
块返回值类型 (^块变量名) (形参类型1, 形参类型2, ...);
块与匿名函数类似,块变量与函数指针类似。
__block修饰的局部变量,块只能访问它,但不可修改它;且在定义块时就已经将这种局部变量的值保存在块中,而不是等到调用块时才去访问、获取它的值,因此,后续程序对局部变量的值的修改,对块没有影响,即便这种修改在调用块之前。#import <Foundation/Foundation.h>
int main(){
@autoreleasepool{
int my = 20;
void (^printMy)(void) = ^(void){
//尝试对局部变量赋值,程序会报错
my = 30; // ①
NSLog(@"%d", my); //访问局部变量是可以的
};
my = 45;
printMy(); //调用块
}
}
将①处代码注释掉,再编译运行上述程序,会输出20,而非45。
__block修饰的局部变量,块内可以修改它;并且,无论何时,块都会直接使用该局部变量本身,而不是将局部变量的值复制到块内。#import <Foundation/Foundation.h>
int main(int argc, char* argv[]){
@autoreleasepool{
__block int my = 20;
void (^printMy)(void) = ^(void){
NSLog(@"%d", my);
my = 30;
NSLog(@"%d", my);
};
my = 45;
printMy();
NSLog(@"%d", my);
}
}
上述程序三次分别输出45、30、30。
块作为函数参数时,无需定义块变量,直接把块作为参数传递给函数即可。出于可读性考虑,通常将块作为函数的最后一个参数。
语法格式:
typedef 块返回值类型 (^块类型)(形参类型1 [形参名], 形参类型2 [形参名], ...);
用途:
#import <Foundation/Foundation.h>
int main(int argc, char* argv[]){
@autoreleasepool{
//定义了一个返回类型为void、形参为NSString*的块类型FKPrintBlock
typedef void (^FKPrintBlock)(NSString*);
//使用块类型定义块变量,并将指定块赋给块变量
FKPrintBlock print = ^(NSString* info){
NSLog(@"%@", info);
};
//使用块类型定义块变量,并将指定块赋给块变量
FKPrintBlock loopPrint = ^(NSString* info){
for(int i = 0; i < 3; ++i){
NSLog(@"%@", info);
}
};
//一次调用两个块
print(@"Objective-C");
loopPrint(@"iOS");
}
}
#import <Foundation/Foundation.h>
typedef void (^FKProcessBlock)(int); //定义一个块类型
//使用FKProcessBlock定义最后一个参数类型为块
void processArray(int array[], unsigned int len, FKProcessBlock process){
for(int i = 0; i < len; ++i){
//将数组元素作为参数调用块
process(array[i]);
}
}
int main(int argc, char* argv[]){
@autoreleasepool{
int arr[] = {2, 4, 6};
//传入块作为参数调用processArray()函数
processArray(arr, 3, ^(int num){
NSLog(@"元素平方为:%d", num * num);
});
}
}