浅谈iOS中的闭包

1.1 用途

       闭包在很多语言中都有应用,它在OC中被叫做Blocks,在Java中被叫做Lambda表达式,也有直接叫做匿名函数的。

           简单的说闭包就是一种带有局部变量的匿名函数。

          在C语言中,函数可以通过函数名直接调用,也可以通过函数指针调用,但是这都需要开发者知道函数的名字(函数指针也需要知道函数名以便在被赋值时得到函数的地址)

          可能你会问,为什么要用闭包呢?一个常见的例子如下:

           实现按钮的回调方法。

int buttonId = 0;

void buttonCallBack(int event){
    NSLog(@"id = %d,event = %d",buttonId, event);
}


        现在把情况扩展到多个按钮,如下:

void buttonCallBack(int buttonId, int event){
    NSLog(@"id = %d,event = %d",buttonId, event);
}

void setButtonCallbacks(){ //工厂方法
    for (int i = 0; i < MAX; i++) {
        buttonId = i;
        setButtonCallBack(i,&buttonCallBack); //省略单个set的方法了,只为说明思路
    }
}


显然回调方法保存了按钮的ID以及回调函数的指针。闭包的出现可以使代码更加简洁,可以直接将回调卸载函数内,而不用再去写回调函数,例子如下:

void setButtonCallbacks(){
    for (int i = 0; i < MAX; i++) {
        setButtonCallbackUsingBlock(i,^(int event){
            NSLog(@"id = %d,event = %d",buttonId, event);
        });
    }
}


注意:当用于函数参数时,Block 应该放在参数列表的最后一个。

下面介绍Blocks的语法:

1.2 语法

Blocks的语法有些晦涩,以至于有fuckingblocksyntax这个网站专门记录语法。

如下是Blocks的语法:

^ 返回值类型 参数列表表达式

比如:

1
^int (int count){return count + 1;}

Blocks是可以进行缩写的,如下

1.2.1 省略返回值类型

当省略返回值类型时,如果反表达式中又return语句就使用该返回值的类型,如果表达式没有return语句就是void类型。

如果有多个return语句,那么其类型必须相同。省略返回值类型后,例子如下:

1
^(int count){return count +1};

1.2.2 省略参数参数列表

如果不使用参数,参数列表也可以省略,例子如下:

1
^void (void) {NSLog(@"helloworld");}

可以省略 返回值类型参数列表缩写为如下的形式:

1
^{NSLog(@"helloworld");}

1.2.2 Block 类型

与C语言中的变量相同,Block类型的变量可以作一下用途。

  • 局部变量
  • 函数参数
  • 静态变量
  • 静态全局变量
  • 全局变量

如下是一个常见的声明Block类型的变量的例子:

1
int (^blk) (int) = ^(int count){return count + 1;}

当然,在函数参数中使用Block类型的变量就可以向函数传递Block,在函数返回值中指定Block类型,可以将Block作为函数的返回值返回。分别对应如下的两个例子:

1
void function (int (^blk) (int))
1
2
3
int (^func())(int) {
    return ^(int count){return count + 1;}
}

到这里,Block的语法变得着实复杂了,可以通过typedef做简化。如下是简化的例子:

1
2
3
4
5
6
7
8
9
10
11
typedef int (^blk_t) (int);

//原来的写法
void func(int (^blk) (int))
//新的写法
void func(blk_t blk)

//原来的写法
int (^func()(int))
//新的写法
blk_t func()

1.2.3 捕获外部变量

Block中捕获外部的局部变量具有瞬间性,即如果变量被Block捕获后修改了值,那么Block中捕获的变量的值并不会改变。

此外,Block无法给捕获的外部变量赋值。

1.2.4 __block修饰符

Block捕获外部的局部变量后,无法改变它的值,使用附有 __block修饰符的局部变量可以在Block中赋值。

1.2.5 注意事项

Block中虽然无法给捕获的局部变量赋值,但是对于OC的对象的一些方法,是可以执行的,比如捕获一个NSMutableArray后,执行addObject方法。这不会有任何问题,因为这相当于捕获了对象的实例指针。

对于C语言中的数组,Block中并没有实现对之的捕获方法。可以使用指针来解决这个问题。

1
2
3
4
5
char *text = "helloworld";

void (^blk)(void) = ^{
    NSLog(@"%c",text[2]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值