1.是什么?
一种特殊的数据类型
2.有什么用?
用于保存代码块
3.怎么用?
>1.声明block的快捷键:
inlineBlock
>2.block的声明:
<#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) { <#statements#> };
>3.声明/初始化/调用
//声明 void(^myBlock1)();//无参无反 int(^myBlock2)();//无参有反 void(^myBlock3)(int);//有参无反 int(^myBlock4)(int,int);//有参有反 //初始化 myBlock1 = ^() { NSLog(@"无参无反"); }; myBlock2 = ^() { return 3; }; myBlock3 = ^(int a) { NSLog(@"%d",a); }; myBlock4 = ^(int a,int b) { return a + b; }; //调用 myBlock1(); int num = myBlock2(); myBlock3(3); int sum = myBlock4(3,4);
>4.给block起别名
返回值类型 (^别名)(参数);
例:
typedef void(^myBlock)();//给第一个无参无反的block起别名myBlock,myBlock就称为一种数据类型
使用:
myBlock block1 = ^(){ NSLog(@"声明和定义不同,声明仅仅是声明一个变量(开辟一块内存空间),并不初始化,定义包含了初始化,像这样即是声明的同时初始化了"); };
像这样仅仅是声明了一个myBlock类型的变量:
myBlock block2;
myBlock block3;
myBlock block4;
因为block是一种数据类型,因此数据类型所具有的所用特性block都具有,可以声明变量;作为参数;作为返回值;
>5.block作为函数参数
>例一:
typedef int(^myBlock2)(); typedef int(^myBlock3)(int);
int sum(myBlock2 m,myBlock3 n,int a)//a为myBlock3需要的参数 { // int num1 = m(); // int num2 = n(a); // return num1 + num2; return m() + n(a); }
//block作为函数参数 myBlock2 m = ^(){ return 10; }; myBlock3 n = ^(int a) { return a; }; int num = sum(m, n, 10); NSLog(@"%d",num);//输出20;
此种方式并不常用.常用的情景是:比如有三个函数,开头和结尾部分执行的代码一样,中间有部分代码不同,那么就可以将中间部分抽取为block,将三个函数变为一个,调用三次该函数,传入不同的block即可.
>例二:
void test1() { NSLog(@"AAAAAAAAAAAAAAAAAAAA"); NSLog(@"星期天,今天去哪儿浪呢?"); NSLog(@"BBBBBBBBBBBBBBBBBBBB"); } void test2() { NSLog(@"AAAAAAAAAAAAAAAAAAAA"); NSLog(@"星期一,昨天玩的好累不想上班."); NSLog(@"BBBBBBBBBBBBBBBBBBBB"); } void test3() { NSLog(@"AAAAAAAAAAAAAAAAAAAA"); NSLog(@"星期二,昨天的任务还没完成"); NSLog(@"BBBBBBBBBBBBBBBBBBBB"); }
通过block优化,分析中间部分代码,不需要参数,返回值,定义无参无反的block:
typedef void(^myBlock)()
将四个函数抽取为一个
void test(myBlock myLife) { NSLog(@"AAAAAAAAAAAAAAAAAAAA");
if(myLife){//判断block是否为nil,否则可能报错,会报什么错呢?,为什么是nil呢,nil不是用于OC对象为空的情况么?block是基本数据类型?还是OC类型?
myLife();
} NSLog(@"BBBBBBBBBBBBBBBBBBBB"); }
main函数中就可以这样写:
test(^(){
NSLog(@"星期天,今天去哪儿浪呢?");
});
test(^(){
NSLog(@"星期一,昨天玩的好累不想上班.");
});
test(^(){
NSLog(@"星期二,昨天的任务还没完成");
});
>6.作为函数返回值
typedef void(^myBlock)(); myBlock test4() { return ^(){ }; }
>7.利用block在不同对象间进行传值
假设A需要传值给B,那么需要在A中定义一个block属性,在需要的时候传递值,先判断是否为nil,不为nil则调用block.
需要在B中声明一个属性(有东西接收就可以,不一定就要定义属性),用以接收传递过来的值,B必须拿到A,比如A成为B的属性,那么就可以获取A的block属性,并定义,判断的时候,block就已经定义了,就可以实现传值了.
例子:
控制器的View上有一个绿色的View,当点击屏幕的时候,传递一个NSInteger数据给控制器.
分析:
绿色的View为数据的传递者,控制器为接收者,因此,需要给绿色的View声明一个block类型的属性,因此自定义一个GreenView的类用于描述绿色的View,并在其中声明block属性
typedef void(^GreenViewBlock)(NSInteger index); @property (nonatomic,copy) GreenViewBlock myBlock;
当点击屏幕的时候传递数据,因而重写touchesBegin方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { if (_myBlock) {//如果实现了,就调用 _myBlock(11); } }
控制器为接收者,因而给控制器声明一个属性用于接收数据,又因为,需要在控制器中初始化block,这样点击屏幕是block不为nil,实现传值,因而需要获得绿色的View的属性block,因而,将绿色的View拖成控制器的属性
@property (nonatomic,assign) NSInteger index;
@property (weak, nonatomic) IBOutlet GreenView *greenView;
//初始化block
_greenView.myBlock = ^(NSInteger index){ self.index = index; };
//上面的赋值操作即是调用index的setter方法,因而此时即可获得传递过来的数据
- (void)setIndex:(NSInteger)index { _index = index; NSLog(@"%ld",index); }
>8.注意:
block内部默认不能修改外部的局部变量
用__block修饰局部变量,在block中就可以访问了.