Skip to content

iOS — Blocks的使用 #14

Open
Open

Description

@cssoul
什么是Blocks

Blocks是C语言的扩充功能。如果用一句话概括就是,带有局部变量的匿名函数(即不带名称的函数)。也称之为闭包。

Blocks语法

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

例如:

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

这个Block非常简单,就是把计数器加一,但麻雀虽小,五脏俱全,语法上一个元素都没漏掉。首先是^符号(插入符号),然后依次是是返回值类型,参数列表,表达式。

一个完整的Block就是这些内容,不同的Block的表达式的复杂程度各异,但元素就是这几个。

不过很多时候我们会遇到没有返回参数,或者没有传入参数,甚至既没有传入参数也没有返回参数的情况。这个时候Block可以省略相关的内容,就是说相对应的那一块不用写了。比如:

没有返回参数,可能就会写成:

  ^(int count){printf("count=%d", count);}

没有参数列表,可能会写成:

  ^int{return 1;}

既没有返回参数也没有参数列表,可能就会写成:

  ^ {
        printf("Hello, blocks");
    }
将Blocks声明为属性

多数情况下,我们会把Blocks声明为属性,便于调用。可以利用关键字typedef 对Blocks进行别名。

typedef 返回值类型 (^Blocks别名)(参数列表);
typedef int (^blk_t)(int);

//将Blocks声明为属性
@property (nonatomic, copy) blk_t blk;

//对Blocks进行声明定义
blk = ^(int count) { return count + 1; };

//调用Blocks 和 调用C语言声明函数方式一样
NSLog(@"%d\n", blk(10));
将Blocks作为参数传入方法中

通常都会事先为Blocks取一个别名,一来方便理解,

//定义:
typedef void(^Block)(int a);

- (void)logWithBlock:(Block)block { 
    if (block) { 
        block(10); 
    }
}


//赋值并调用
[object logWithBlock:^(int a) { 
    NSLog(@"%d", a);
}];
Blocks截获自动变量值

什么是截获自动变量值,所谓自动变量,就是局部变量。那为什么会截获呢?先来看个例子。

int val = 1;
void  (^block)(void) = ^ { printf("val = %d", val); };
val = 2;
block();  //此处调用block,打印为val = 10;

在这里,运行结果是val=1。请注意,虽然这个时候val的值已经变成了2,但Block里面仍然是1,也就是说,Block在定义时相当于对val这个变量进行截获,也就是说,把val拷贝一份存入Blocks中。所以当外部val进行了修改时,不影响Blocks截获的val值。

Blocks截获自动变量值

另外需要说明的是,Block里面不能改变val这个变量的值,如果你试图改变,编译器会报错,换句话说,Block里面,val就是只读的,而且值就是定义时的那个。

__block 关键字

从上个例子中,我们知道Blocks会对变量进行截获。那如果我非要在Blocks中修改外部参数怎么办呢?我们可以通过__block关键字做到!

__block int val = 10;
void  (^block)(void) = ^ { printf("val = %d", val); };
val = 20;
block();  //此处调用block,打印为val = 20;

这段代码和上一段的区别仅仅是多了__block的声明,但运行结果就是val=2了,也就是说,Block能跟踪val的变化了。

Blocks截获自动变量值

通过__block说明符对外部参数进行声明后,实际上,相当于在声明定义Blocks的时候,不是通过拷贝内存的方式拷贝外部参数,而是通过指针指向该外部变量,从而达到可以在Blocks中修改的效果。

在一个Block里面,往往两种变量都需要有,具体怎么使用,就看具体的情况了。

总结:
  • 因为Blocks是匿名函数,所以在多人合作时候代码容易凌乱,最好是多使用注释说明;
  • Blocks使用方便,但是block的内存管理非常容易出错,稍不注意便会造成内存泄露,所以,在使用Blocks的时候,小心谨慎为妙。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions