Block

简介

Block本质上是指向一个结构体的指针。Block可以形象的比作一个函数体。使用代Block你可以像调用其他标准函数一样,传入参数数,并得到返回值。但是它远比函数更加强大。

循环引用

1.如果没有对block进行copy操作,block就存储于栈空间

2.如果对block进行copy操作,block就存储于堆空间

3.如果block存储于栈空间,不会对block内部所用到的对象产生强引用

4.如果block存储于堆空间,就会对block内部所用到的对象产生强引用

当block中的对象被强引用时,导致循环引用,内存无法释放

解决方法:使用__weak 指向对象

1
2
3
4
5
6
Person *p = [[Person alloc] init];
// 解决循环引用
__weak typeof(p) weakP = p;
p.testBlock = ^{
[weakP run];
};

定义

1
2
3
4
返回值类型(^block变量名)(形参列表) = ^(形参列表) {
};
调用Block保存的代码
block变量名(实参);

简单用法

1.无参数无返回值的Block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 无参数无返回值的Block
*/
-(void)func1{
/**
* void :就是无返回值
* emptyBlock:就是该block的名字
* ():这里相当于放参数。由于这里是无参数,所以就什么都不写
*/
void (^emptyBlock)() = ^(){
NSLog(@"无参数,无返回值的Block");
};
emptyBlock();
}

2.有参数无返回值的Block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 调用这个block进行两个参数相加
*
* @param int 参数A
* @param int 参数B
*
* @return 无返回值
*/
void (^sumBlock)(int ,int ) = ^(int a,int b){
NSLog(@"%d + %d = %d",a,b,a+b);
};
/**
* 调用这个sumBlock的Block,得到的结果是20
*/
sumBlock(10,10);

3.有参数有返回值的Block

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 有参数有返回值
*
* @param NSString 字符串1
* @param NSString 字符串2
*
* @return 返回拼接好的字符串3
*/
NSString* (^logBlock)(NSString *,NSString *) = ^(NSString * str1,NSString *str2){
return [NSString stringWithFormat:@"%@%@",str1,str2];
};
//调用logBlock,输出的是 我是Block
NSLog(@"%@", logBlock(@"我是",@"Block"));

界面传值

在项目开发中,会遇见在B控制器完成输入操作之后返回到A控制器,同时需要拿到B控制器的数据。这种情况可以使用代理,通知,Block解决。本文以Block方式来举例。

B控制器

.h文件

1
2
3
4
5
// 定义一个名为TextBlock的Block
typedef void (^TextBlock) (NSString *showText);

// 声明一个TextBlock类型的Block
@property (nonatomic, copy) TextBlock textBlock;

.m文件

1
2
3
4
5
6
7
// 当view即将消失时,调用block
- (void)viewWillDisappear:(BOOL)animated {

if (self.textBlock != nil) {
self.textBlock(self.inputTF.text);
}
}

A控制器

1
2
3
4
5
6
7
8
9
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

TextFieldViewController *tfVC = segue.destinationViewController;
__weak typeof(self) weakSelf = self;
// 控制器跳转前,为下一个控制器的Block定义回调的操作
tfVC.textBlock = ^(NSString *showText){
weakSelf.showLabel.text = showText;
};

逻辑整理:在A控制器中事先定义好需要在B控制器执行的操作,然后B在恰当的时机进行调用。