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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值