小括号后面的大括号中写要封装的代码,且代码可以使用小括号中的参数。 下面举一个求两个数的和的代码封装过程。
typedef int (^BlockType)(int a,int b);
BlockType varBlock;
varBlock = ^(int a,int b){return a+b;};
将代码存入varBlock变量中后,便可以使用该变量调用代码。
int a = 4;
int b = 6;
int sum = varBlock(a,b);
NSLog(@"sum = %d",sum);//输出结果为10
Block变量也可以给同类型的变量赋值
BlockType varBlockTemp;
varBlockTemp = varBlock;
int sum = varBlockTemp(1,2);
NSLog(@"sum = %d",sum);//输出结果为3
将一段代码当做一个变量进行传递,Block这样的特性极大的方便了我们之后的编码工作
3,Block变量对普通变量作用域的影响
通过Block对象将代码进行封装的同时,有一个非常关键的问题我们需要明确讨论,即Block变量对普通变量作用域的影响。
通过一个简单案例来因此这个问题。见如下代码:
main()
{
{
int a = 1;
{
a = 2;
}
//此处输出a的值为2
}
//此处已经超出变量a的作用域,讨论a的值无意义。
}
这段代码很简单,通过大扩展来表示变量的作用域范围。再看下面代码:
typedef void (^ BlockType)(void);
BlockType var;
void fun1()
{
int a = 10;
var = ^(){NSLog(@"a = %d",a)};
}
void fun2()
{
var();
}
main()
{
fun1();
fun2();
}
在fun2函数中调用var变量时,运行的是fun1中存入var变量的代码,且代码中的使用的变量a也是fun1中的局部变量。
正常状态下,变量a的作用域在fun1函数体大括号内。在函数体大括号外面使用a是没有意义的。
但此处情况特殊,变量a被block变量var所使用,所以var变量将a进行了一个复制操作,也就是我们在var的代码里面使用的a其实是a的副本。
我们看下面的代码:
typedef void (^ BlockType)(void);
BlockType var;
void fun1()
{
int a = 10;
var = ^(){NSLog(@"a = %d",a)};
a = 20;
}
void fun2()
{
var();
}
main()
{
fun1();
fun2();
}
这段代码的输出和上一段代码一样,不会因为fun1函数中a的值发生变化而导致block里面的a的值发生变化。原因是Block变量在使用局部变量是,会对局部变量进行一个复制操作,block变量中储存的代码使用的时局部变量的副本。
但是在某些特殊场合,我们需要改变局部变量可以引起block变量中代码的变化。这时候我们需要使用block全景变量。
block全景变量通过:__block来声明。
typedef void (^ BlockType)(void);
BlockType var;
void fun1()
{
__block int a = 10;
var = ^(){NSLog(@"a = %d",a)};
a = 20;
}
void fun2()
{
var();
}
main()
{
fun1();
fun2();
}
上文代码中,fun1中的变量a被block全景变量标识符所修饰,即变量a成为一个block全景变量。
其作用是,此时block封装代码时使用a变量,不会进行复制操作,也就表示,局部变量a与block代码中的a为同一个变量。所以,当前代码的运行结果为 a = 20。
4,Block回调接口使用
回调的本质为控件反馈自身信息,在面向对象编程中,控件需要调用方法反馈自身信息,而方法必须从属某个对象。所以之前的回调接口必须设置两个参数,一个反馈对象,一个反馈方法。