Block是一个很好用的东西,这篇文章主要来介绍:1.什么是Block?2.Block的使用?3.Block的循环引用问题及解决.
1.什么是Block?
闭包(Closure)。闭包就是一个函数,或者一个指向函数的指针,加上这个函数执行的非局部变量。说的通俗一点,就是闭包允许一个函数访问声明该函数运行上下文中的变量,甚至可以访问不同运行上文中的变量。
Block实际上就是OC语言对闭包的实现。
下面声明一个Block:
1 int (^Sum)(int, int);
首先,第一个int也就是该Block的返回值类型,也可以是其他的返回值类型,或者无返回值。“^”是Block的标识。第二以及第三个int,则是Block的参数类型,当然也可以无参数。
下面的代码则是定义了一个Block,当执行Line5代码时,会输出“nihao”,也就是给Block传入的参数。
1 void (^printBlock)(NSString *) = ^(NSString *str) {
2 NSLog(@"%@", str);
3 };
4
5 printBlock(@"nihao");
下面借鉴一张网上流传的图片总结一下Block的结构:
__block
2.Block的使用
2.1 使用Block在不同的页面进行传值
页面传值有很多方式,比如:属性、单例、通知、代理,Block等。这里单说使用Block传值,其他几种以后再做补充。
使用Block传值也有两种方式:Block属性和使用Block作为参数的方法。
2.1.1 使用Block属性传值
下面演示的是从B页面(后一个页面)传值到A页面(前一个页面)。
首先在B页面中声明一个Block,通常为了使代码简洁,我一般会对Block进行重定义:
typedef void (^PassVal)(NSString *text);
接着,在B中声明一个Block属性:
@property (nonatomic, copy) PassVal passVal;
这里需要注意下,我使用了copy,实际上在ARC环境下,使用copy和strong都是可行的。我这里只是为了表明,使用Block时,实际上是把Block从栈区拷贝到了堆区。
下面继续。我这里选择在B页面即将消失时,将值传出:
1 - (void)viewWillDisappear:(BOOL)animated {
2 if (self.passVal) {
3 self.passVal(@"1234567898");
4 }
5 }
我们可以看一下前面声明的Block是一个有参(string类型),无返回值。这里我给Block的参数是@"123456798"。通过上面的处理,B页面的操作已经完成了。下面进行A页面的操作:
- (void)btnNextAction:(UIButton *)btnNext {
BViewController *BVC = [[BViewController alloc] init];
BVC.passVal = ^(NSString *text) {
NSLog(@"%@",text);
};
[self.navigationController pushViewController:BVC animated:YES];
}
上面的代码演示了,在点击按钮即将push到B页面时,来实现Block。这样就可以在A页面中得到B页面的值,也就是text值。到此,Block属性传值结束。
2.1.2 使用带有Block参数的方法传值
这种方式和属性传值类似,下面做简单的示例:
1 typedef void (^PassVal)(NSString *text);
2
3 @interface SecondViewController : UIViewController
4
5 @property (nonatomic, copy) PassVal passVal;
6
7 - (void)returnText:(PassVal)block;
8
9 @end
首先在第二个页面同样需要声明Block属性,同时在第二个页面声明一个方法,方法的参数即是属性同样类型的Block。接着实现下面的方法:
1 - (void)viewWillDisappear:(BOOL)animated {
2 if (self.passVal) {
3 self.passVal(@"1234567898");
4 }
5 }
6
7 - (void)returnText:(PassVal)block {
8 self.passVal = block;
9 }
首先要做的还是先给Block的参数赋值,接着要实现声明的方法。接下来去第一个页面操作:
1 - (void)btnNextAction:(UIButton *)btnNext {
2 SecondViewController *secCtr = [[SecondViewController alloc] init];
3 [secCtr returnText:^(NSString *text) {
4 NSLog(@"%@",text);
5 }];
6
7 [self.navigationController pushViewController:secCtr animated:YES];
8 }
这样也可以实现传值。
使用方法传值,猛一看觉得挺麻烦,但是实际上,使用方法调用的方式是很容易理解的。
传值只是Block的简单应用,总体来说,Block和代理的使用时很类似的,可以互相参考着学习。
3.Block的循环引用问题及解决.
self.
__weak typeof(self)weakSelf = self;
[self.tableView addHeaderWithCallback:^{
weakSelf.isDown = YES;
weakSelf.page = 1;
[weakSelf requestData];
}];
也就是说,把需要使用self的地方换成weakSelf即可.如果是MRC,只需要把上面代码的第一行更换为:
__block typeof(self)weakSelf = self;
以上仅作为各位使用的参考,如果有不到位的地方,欢迎各位留言指出,大家一起交流.