OC块(Block)

Posted Billy Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OC块(Block)相关的知识,希望对你有一定的参考价值。

什么是块

块是O-C对ANSI C所做的拓展,使用块可以更好地简化O-C编程,而且O-C的很多API都依赖于块。

块的基本语法

定义块的语法格式如下:

^ [块返回值类型] (形参类型1 形参1, 形参类型2 形参2, ...)
{
	//块执行体
}

定义块的语法非常像定义一个函数,但只是定义一个匿名函数。

  • 定义块必须以^开头。
  • 定义块的返回值类型可以省略,且通常省略声明块的返回值类型。
  • 定义块无需指定名字
  • 如果块无返回值,块无须带参数,通常建议使用void作为占位符。

定义块变量的语法:

块返回值类型 (^块变量名) (形参类型1, 形参类型2, ...);

例:

#import <Foundation/Foundation.h>

int main(int argc , char * argv[]){
	@autoreleasepool{
		//定义不带参数,无返回值的块
		void (^printStr) (void) = ^(void){
			NSLog(@"我正在学习O-C的块");
		};
		//
		double (^hypot)(double , double)= ^(double num1, double num2){
			return sqrt(num1 * num1 + num2 * num2);
		};
		printStr();
		//调用块,并输出返回值
		NSLog(@"%g",hypot(3,4));
		//也可以先只定义块变量:定义带参数、无返回值的块
		void (^print)(NSString*);
		//再将块赋给指定的块变量
		print = ^(NSString* info){
			NSLog(@"info参数为:%@" , info);
		};
		//调用块
		print(@"学习块的知识");
	}
}

程序不仅可以在定义块变量的同时对块变量赋值,也可以定义块变量,再对块变量赋值。
块变量与函数指针非常相似;而块则非常像一个匿名函数。当程序调用块时,调用块的语法与调用函数完全相同。从这个角度看,完全可以把块当成一种简化的函数。
编译、运行该程序,可以看到如下输出:

我正在学习O-C的块
5
info参数为:学习块的知识

块与局部变量

块可以访问程序中局部变量的值,当访问局部变量的值时,不允许修改局部变量的值。

#import<Foundation/Foundation.h>
int main (int argc, char * argv[]){
	@autoreleasepool{
		int my = 20;
		void (^printMy)(void) = ^(void) {
			//尝试对局部变量赋值,程序将会报错
			//my = 30;
			NSLog(@"%d" , my);
		};
		my = 45;
		printMy();//调用块
	}
}

运行结果是45
再看下一段程序,为局部变量增加__block修饰

#import<Foundation/Foundation.h>
int main (int argc, char * argv[]){
	@autoreleasepool{
		__block int my = 20;
		void (^printMy)(void) = ^(void) {
			//运行时访问、获取局部变量的值输出45
			NSLog(@"%d" , my);
			//尝试对局部变量赋值是允许的
			my = 30;
			NSLog(@"%d" , my);
		};
		my = 45;
		printMy();//调用块
		//由于块修改了__block局部变量的值,因此下面的代码输出30.
		NSLog(@"块执行完后,my的值为:%d",my);
	}
}

输出结果是:

45
30
30

说明已经修改了局部变量的值。

直接使用块作为参数

当把块作为方法参数时,无须定义块变量,直接把块作为参数传递给指定的方法即可,但块只能作为方法的最后一个参数。

使用typedef定义块变量类型

使用typedef可以定义块变量类型,一旦定义了块变量类型,则有两个主要用途:

  1. 复用块变量类型,重复定义多个变量
  2. 定义函数参数,可以定义带块参数的函数

示例:

#import<Foundation/Foundation.h>
int main(int argc , char * argv[]){
	@autoreleasepool{
		//使用typedef定义了块变量类型
		typedef void (^FKPrintBlock)(NSString*);
		//使用FKPrintBlock定义块变量,并将指定块赋给该变量
		FKPrintBlock print = ^(NSString* info){
			NSLog(@"%@" , info);
		}
		FKPrintBlock loopPrint = ^(NSString* info){
			for (int i = 0; i < 3; i++){
				NSLog(@"%@" , info);
			}
		};
		//依次调用两个块
		print(@"Objective-C");
		loopPrint(@"ios");
	}
}

此外,利用typedef定义的块变量类型即可为函数声明块变量类型的形参,这要求调用函数时必须传入块变量。
示例:

#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()函数
		processArry(arr, 3, ^(int num){
			NSLog(@"元素平方为:%d",num*num);
		});
	}
}

输出为:

元素平方为:4
元素平方为:16
元素平方为:36

以上是关于OC块(Block)的主要内容,如果未能解决你的问题,请参考以下文章

OC基础:block.字面量

iOS学习之代码块(Block)

高效 OC开发之Block和GCD

Sphinx - 在代码块片段中使用省略号 (...)

IOS开发-block的使用

关于block块使用的6点注意事项