一. block类型的变量的声明.
返回值类型(^block变量名)(参数列表);
void (^myBlock)();
表示声明了1个block类型的变量变量名叫做myBlock
这个myBlock变量只能存储无返回值无参数的代码段.
void (^myBlock1)(int num1,int num2);
表示声明了1个block类型的变量叫做myBlock1
这个myBlock1变量之中可以存储无返回值带两个int类型的参数的代码段.
int (^myBlock2)(int num1,int num2);
二. block变量的初始化.
2).如何写1个符合要求的代码段.
语法:
^返回值类型(参数列表){
代码;
};
a.无参数无返回值的代码段.
^void(){
NSLog(@"呵呵1");
NSLog(@"随便2");
};
完全可以将这个代码段通过赋值符号存储到符合要求的block变量之中.
void (^myBlock1)();
myBlock1 = ^void(){
NSLog(@"呵呵1");
NSLog(@"随便2");
};
当然完全可以在声明block变量的同时直接赋值.
b.无返回值,有参数的代码段的书写.
^void(int num1,int num2){
int num3 = nim1 + num2;
NSLog(@"num3 = %d",num3);
};
void (^myBlock2)(int num1,int num2) = ^void(int num1,int num2){
int num3 = nim1 + num2;
NSLog(@"num3 = %d",num3);
};
c.有返回值有参数的代码段的书写.
^int(int num1,int num2){
int num3 = num1 + num2;
return num3;
};
int (^myBlock3)(int num1,int num2) = ^int(int num1,int num2){
int num3 = num1 + num2;
return num3;
};
为block变量赋值代码段的时候,代码段必须符合block变量的返回值和参数的要求.
否则就会报错.
三.执行存储在block类型变量中的代码.
1).如何执行?
在要执行的地方加上代码: block变量名();
如果存储在block变量中的代码段有参数,那么给参数就可以了.
如果有返回值,使用1个相应类型的变量接收返回值就可以了.
6.使用block注意小点.
1).如果代码段没有参数.那么代码段可以省略表示参数列表的小括弧.
void (^myBlock)() = ^void{
NSLog(@"呵呵");
};
2).如果声明block变量的时候,要求代码块带参数.那么在声明block变量的时候.可以只写参数类型,省略参数名称.
但是代码段是必须要写参数名字的.
void (^myBlock)(int,int) = ^void(int num1,int num2){
NSLog(@"%d + %d = %d",num1,num2,num1+num2);
};
3).代码段的返回值类型可以省略.
int (^myBlock)(int,int) = ^(int num1,int num2){
return num1 + num2;
};
如果代码段没有指定返回类型.那么这个代码段的返回值类型就是return回去的数据的类型.
如果没有return那么这个代码段就的返回值就是void.
void (^block1)() = ^{
.....
};
7.使用typedef将复杂的block定义简化.
1).遇到的问题.
如果我们希望定义1个无返回值无参数的block变量.
void (^myBlock1)();
如果再希望定义1个呢?
void (^myBlock2)();
如果再希望定义1个呢?
void (^myBlock2)();
...........
你有没有发现,每次定义block变量要使用好长的1段代码,忒麻烦.
2).我们学习过typedef给已经存在的类型取1个别名.
我们可以为1个指定要求的block取1个短别名.然后使用这个别名声明多个要求一致的block变量.
废话不说,看例子.
typedef void (^newType)();
代表为返回值为void并且没有参数的block类型定义了1个别名叫做newType.
如果我们想声明1个没有返回值并且参数的block.直接使用别名newType就可以定义.
比如:
newType myBlock;
首先,myBlock是1个变量.1个block类型的变量.这个变量要求存储的代码段无返回值并且没有参数.
所以,可以像下面这样初始化.
myBlock = ^{
NSLog(@"呵呵");
};
调用按原来的就方式就可以调用.
myBlock();
------------再次举例-----------------
typedef int (^newType)(int,int);
代表为返回值为int类型,参数有两个int类型的参数的block类型定义了1个别名叫做newType.
如果我们要声明1个返回值为int,并且参数是两个int类型的block变量的时候,
就可以使用newType来直接简单声明
newType sumBlock = ^(int num1,int num2){
return num1 + num2;
};
调用block
int sum = sumBlock(10,20);
四. block访问外部变量.
1).全局变量.局部变量. block内部变量.重名及各自的作用域.
2).默认情况下,block内部可以取外部的变量的值.
但是无法修改外部变量的值.
可以修改全局变量,但是无法修改外部的局部变量.
3).如果允许外部变量的值在block内部可以被修改,那么就将外部变量使用__block修饰.
默认情况下block外部的局部变量只允许在block内存的取值访问,不允许在block内部改值.
如果就是要允许外部的局部变量可以改
用__block来修饰外部的局部变量.
五,block作为函数的参数
1. block是1个数据类型. 所以block类型完全可以作为函数的参数或者返回值.
2. block作为函数的参数. (他的作用就是让调用者自己控制代码的实现,比如实现两个数的和与乘积)
1). 形参就直接声明1个符合要求的block变量就可以了.如果觉得恶心,可以使用typedef简化定义.
2). 实参代码段的要求必须要和形参的要求一致.
如果形参是1个无返回值无参数的block 那么实参的代码段也必须要符合这个要求.
3). 在传值的时候.
a. 先将符合要求的代码段存储在1个block变量之中 然后再传递block变量.
b. 也可以直接传递符合要求的代码段.
3. block作为函数的参数可以实现的效果.
可以让调用者传递1段代码到函数的内部. 在函数的内部执行这段代码.
void sum(int a, int b, void(^block)(int c)){
int sum = a + b;
// 回调block
block(sum);
}
// 调用函数
sum(20, 10, ^(int c) {
NSLog(@"sum=%d",c);
});
上面只是一个小例子,在第申明函数的内部,把求和的结果放在了block里面,相当于求和的代码块放在了block里面,当我们调用函数的时候,就可以使用这个存放在block里面的代码块。
3. block与函数的异同
1). 相同点: 都可以封装1段代码在其中.
2). 不同点:
a. block是1个数据类型. 而函数就是函数.
b. block可以作为函数的参数传递。而函数不能直接作为参数传递.
c. block可以嵌套.函数不能嵌套定义.
4 ,blcok作为函数的返回值
步骤是:1 定义一个新的blcok数据类型
2 新的block数据类型作为函数的返回值
3 调用函数
4 回调block
//相当于定义一个void类型的无参数的block数据类型 新的数据类型名为NewType
typedef void (^NewType)(); // 第一步
NewType test() // 第二步
{
void (^block)() = ^{
NSLog(@"哈哈哈哈哈哈哈");
NSLog(@"呵呵呵呵呵呵呵");
};
return block;
}
// 调用函数
NewType bType = test(); // 第三步
bType(); // 第四步
再深入理解的Block,可以看下下面3篇文章,写的很好。
http://my.oschina.net/leejan97/blog/268536
http://my.oschina.net/leejan97/blog/262855
http://my.oschina.net/leejan97/blog/209762