今天来给大家简单讲解一下block的用法,在讲解block之前,我们先来理解一下闭包的概念
1.闭包的概念
我们先来看一下脚本语言的闭包
function funA(callback){
alert(callback());
}
function funB(){
var str = "Hello World"; // 函数funB的局部变量,函数funA的非局部变量
funA(
function(){
return str;
}
);
}
对脚本语言不是很熟悉的同学就很疑惑,这是什么?感觉语法不通的样子
其实,网上对闭包的解释大多都很狭隘,我觉得最经典的还是维基百科给出的解释。
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。 Peter J. Landin 在1964年将术语闭包定义为一种包含环境成分和控制成分的实体。
通俗来讲,就是闭包允许函数作为一个参数传递给一个函数,或者是作为一个变量传递给另一个变量
我们再来看一下C语言中的例子
#include <stdio.h>
#include <stdlib.h>
int main()
{
int max(int,int);
int (*p)(int,int);
int a,b,c;
p = max;
scanf("%d,%d",&a,&b);
c = (*p)(a,b);
printf("a=%d,b=%d,max=%d\n",a,b,c);
return 0;
}
int max(int x,int y)
{
int z;
if(x>y) z = x;
else z = y;
return(z);
}
是不是超级眼熟呢,有同学就问了,什么鬼?这不就是指向函数的指针么?
其实说白了,闭包就是指向函数的指针,然后用指针去访问这个函数。其实语言在很多方面都是相通的,大家不要去纠结,如果一个概念你不能理解,但你仍然能够很好地使用它,那就不用去理解,只要知道如何使用就好了。就像我们不用了解电脑的内部构造,我们只要能够很好地使用电脑完成我们的工作就够了。
如果大家能够认识到闭包就是指向函数的指针,那下面就很好理解了
2.Block的基本语法
Block从本质上来说就是Object-C对闭包的实现
我们看一下Block的原型
void ( ^myBlock )( ) = ^(){ };
其实和函数的指针差不了多少,我们用一张图来详细解释一下
注意:这里只是对Block的声明与实现,可以再代码的任意地方,在进行调用之前,这里面的代码不会执行,而且外部的参数也不能在里面修改
什么意思呢?比如说:
int number = 10;
// = 右边的实现部分,无需写上返回值类型
int (^sumBlock)(int, int) = ^(int a, int b) {
number = 15; //在这里number是无法被修改的
return a + b;
};
// 告诉编译器,number 可能要在block中进行使用
int __block number = 10;
基本语法我们已经知道了,下面我们就来进行一个小小的实战
3.Block的使用
场景:有一个母亲和保姆,在母亲外出的时候,需要保姆照顾婴儿
1>创建一个保姆类
Nanny .h
#import <Foundation/Foundation.h>
@interface Nanny : NSObject
- (void)lookAfterBaby;
@end
Nanny .m
#import "Nanny.h"
@implementation Nanny
- (void)lookAfterBaby
{
NSLog(@"照看Baby");
}
@end
2>创建Mother类
#import <Foundation/Foundation.h>
// block的声明 和 调用是写在主动方所在的类
@interface Mother : NSObject
// block 属性的写法
// @property (nonatomic, copy) 返回值类型 (^Block名称)(形参表);
@property NSString *name;
@property (nonatomic, copy) void (^actionBlock)();
// block 作为方法形参的写法
// 方法名:(block类型)block名称
- (void)goOutsideWithAction:(void (^)())action;
@end
#import "Mother.h"
@implementation Mother
- (void)goOutsideWithAction:(void (^)())action
{
NSLog(@"mother 要外出");
action();
}
@end
3>在main.m 文件中调用
Mother *mother = [[Mother alloc] init];
Nanny *Nanny = [[Nanny alloc] init];
// block可以把紧密关联的事件逻辑,放在一起
// block可以极大的降低耦合度
[mother goOutsideWithAction:^{
[Nanny lookAfterBaby];
}];
总结:
1.Block 就是Object-C对闭包的实现,在java中就是匿名类,在C语言中就是指向函数的指针
2.Block 的原型就是把指向函数的指针中的 * 修改为 ^ 就可以了
3.Block 只是声明和实现了函数,可以存在代码的任意地方,如果想要函数执行,需要另外调用
4.在Block 中,默认是不允许修改外部变量,如果需要修改,应在声明变量的时候加上 __block ,告诉编译器,变量要在Block中使用