iOS之Block
2015-10-10 23:31
483 查看
iOS中的Block机制,可以简化程序,实现回调功能。跟C语言中的函数指针类似。可以通过传递Block实现函数的回调处理。
简单地例子:
定义一个block
int(^myblock)(int a, int b);
解释:定义了一个block,名称是myblock(类似函数指针),它的返回类型是int,传入2个int型的a,b的参数。
定义函数指针具体要做的内容。(函数体)
myblock = ^(int a, int b){
retrun a+b;
};
解释:定义了myblock的具体功能,根据传入的2个int型参数,求和返回。
再看一个复杂一点的对象参数block。
这个block完成的功能是:连接2个字符串。
//简单实例3
NSString*(^concatString)(NSString *s1,NSString *s2) = ^(NSString *s1, NSString *s2){
return [s1 stringByAppendingString:s2];
};
NSLog(@"%@",concatString(@"hello",@" world")); //打印:hello world
block作为函数的参数使用:
-(void)blockParams:(int(^)(int value)) my_block; //参数是一个block,block的返回值是int,它有一个int的参数。
实现代码:
-(void)blockParams:(int (^)(int))my_block{
my_block(4);
}
在程序中用到更多地关于block的方式,是block回调。就是将block的地址传递到另一个界面,在另一个界面处理好相关数据后,需要回传一些数据给
前一个界面,然后让前一个界面去处理。这样的业务逻辑很常见。
举个栗子:
用户注册时,进行地址的选择,需要从当前A界面跳转到地址列表中(另一个界面B),选择好自己的地址后,需要将地址回传到第一个界面A去处理。
这个时候可以用block来完成这个操作。当然。使用代理protocal也是可以做到的。这里讨论block。
具体写法如下:
在B中定义一个block。
这里使用typedef关键字去建立。typedef void(^myBlock)(int a, int b);
B界面的.h文件如下:
B界面的.m文件如下:
B界面已经全部写好了,现在需要在A界面去调用B界面的方法。写法如下:
SecondViewController *svc = [[SecondViewController alloc]init];
[svc getTwoNumber:^(int a, int b) {
NSLog(@"value a,b : %d,%d",a,b);
}];
[self.navigationController pushViewController:svc animated:YES];
这样就实现了回调。其实上面在A界面调用svc的getTwoNumber的方法时,就已经回调了。
其实应该在B未来某个不确定的时间里,去回调block。怎么做。
在B中声明一个b_myblock,保存住A传过来的block地址就可以了。代码如下:
在B界面中,定义了一个按钮,添加了点击事件。点击时,就会传入参数,回调A中的block,在A中去处理参数。
关于__block关键字的使用与解释:
什么情况下使用__block关键字?
比对下面2段代码:
上面的代码说明什么情况下使用__block关键字。
在block内部使用非局部变量prefix_string时,如果不对prefix_string本身做修改的话,是不用加上__block关键字的。
如果要在block内部修改非局部变量,请务必加上__block。如果不加上,编译器也会报错的。
当一个非局部变量声明成了__block,在block体内操作这个非局部变量,对外面的这个非局部变量同样产生影响,改变它的值。
当没有使用__block定义非局部变量时,在block体中,就会产生一个非局部变量的副本,此时,block形成了闭包。
在block外对非局部变量操作时,不会影响block里面的值。
如果加了__block,此时对外部的非局部变量操作,会同时影响block内的变量值。
测试代码:
第一段代码输出是:
RED_FOOT RED
BLUE_FOOT BLUE
第二段代码输出是:
RED_FOOT RED
RED_FOOT BLUE
由上面可以很好的理解__block的作用,以及程序闭包,对upvalue(非block内部的局部变量)值的副本建立。
====================华丽丽的分割线=========================
总结:block将函数进行封装,并且可以通过传递block的引用的方式,大大的便利了程序的开发。
可以在程序的任意地方,使用block来完成回调处理事件。而block的闭包机制,也可以给block的安全性
带来极大的便利。不会因为外部对非局部变量的操作,引起block内部的错乱。block类似于函数指针,
对block的合理利用,很大程度上的提高程序的可读性。
简单地例子:
定义一个block
int(^myblock)(int a, int b);
解释:定义了一个block,名称是myblock(类似函数指针),它的返回类型是int,传入2个int型的a,b的参数。
定义函数指针具体要做的内容。(函数体)
myblock = ^(int a, int b){
retrun a+b;
};
解释:定义了myblock的具体功能,根据传入的2个int型参数,求和返回。
再看一个复杂一点的对象参数block。
这个block完成的功能是:连接2个字符串。
//简单实例3
NSString*(^concatString)(NSString *s1,NSString *s2) = ^(NSString *s1, NSString *s2){
return [s1 stringByAppendingString:s2];
};
NSLog(@"%@",concatString(@"hello",@" world")); //打印:hello world
block作为函数的参数使用:
-(void)blockParams:(int(^)(int value)) my_block; //参数是一个block,block的返回值是int,它有一个int的参数。
实现代码:
-(void)blockParams:(int (^)(int))my_block{
my_block(4);
}
在程序中用到更多地关于block的方式,是block回调。就是将block的地址传递到另一个界面,在另一个界面处理好相关数据后,需要回传一些数据给
前一个界面,然后让前一个界面去处理。这样的业务逻辑很常见。
举个栗子:
用户注册时,进行地址的选择,需要从当前A界面跳转到地址列表中(另一个界面B),选择好自己的地址后,需要将地址回传到第一个界面A去处理。
这个时候可以用block来完成这个操作。当然。使用代理protocal也是可以做到的。这里讨论block。
具体写法如下:
在B中定义一个block。
这里使用typedef关键字去建立。typedef void(^myBlock)(int a, int b);
B界面的.h文件如下:
1 #import <UIKit/UIKit.h> 2 3 typedef void(^myBlock)(int a, int b); 4 5 @interface SecondViewController : UIViewController 6 7 -(void)getTwoNumber:(myBlock) block; 8 9 @end
B界面的.m文件如下:
1 #import "SecondViewController.h" 2 3 @implementation SecondViewController 4 5 - (void)viewDidLoad { 6 [super viewDidLoad]; 7 // Do any additional setup after loading the view from its nib. 8 self.view.layer.backgroundColor = [UIColor blueColor].CGColor; 9 } 10 11 -(void)getTwoNumber:(myBlock) block{ 12 //假设此处有复杂的操作,最终获得2个值,x,y。 13 int x = 12; 14 int y = 13; 15 16 //将x,y回传调用A界面定义的block方法去处理。 17 block(x, y); 18 19 } 20 21 - (void)didReceiveMemoryWarning { 22 [super didReceiveMemoryWarning]; 23 // Dispose of any resources that can be recreated. 24 } 25 26 @end
B界面已经全部写好了,现在需要在A界面去调用B界面的方法。写法如下:
SecondViewController *svc = [[SecondViewController alloc]init];
[svc getTwoNumber:^(int a, int b) {
NSLog(@"value a,b : %d,%d",a,b);
}];
[self.navigationController pushViewController:svc animated:YES];
这样就实现了回调。其实上面在A界面调用svc的getTwoNumber的方法时,就已经回调了。
其实应该在B未来某个不确定的时间里,去回调block。怎么做。
在B中声明一个b_myblock,保存住A传过来的block地址就可以了。代码如下:
1 #import <UIKit/UIKit.h> 2 3 typedef void(^myBlock)(int a, int b); 4 5 @interface SecondViewController : UIViewController 6 7 @property (strong, nonatomic) myBlock b_myblock; 8 9 -(void)getTwoNumber:(myBlock) block; 10 11 @end
在B界面中,定义了一个按钮,添加了点击事件。点击时,就会传入参数,回调A中的block,在A中去处理参数。
1 #import "SecondViewController.h" 2 3 @implementation SecondViewController 4 5 - (void)viewDidLoad { 6 [super viewDidLoad]; 7 // Do any additional setup after loading the view from its nib. 8 self.view.layer.backgroundColor = [UIColor blueColor].CGColor; 9 } 10 11 -(void)getTwoNumber:(myBlock) block{ 12 _b_myblock = block; 13 } 14 - (IBAction)buttonClick:(id)sender { 15 int x = 12; 16 int y = 13; 17 18 //将x,y回传调用A界面定义的block方法去处理。 19 _b_myblock(x, y); 20 } 21 22 - (void)didReceiveMemoryWarning { 23 [super didReceiveMemoryWarning]; 24 // Dispose of any resources that can be recreated. 25 } 26 27 @end
关于__block关键字的使用与解释:
什么情况下使用__block关键字?
比对下面2段代码:
1 // ======================== 2 NSString* prefix_string = @"HEAD"; 3 NSString*(^concatString)(NSString* foot); 4 concatString = ^NSString *(NSString *foot){ 5 return [prefix_string stringByAppendingString:foot]; 6 }; 7 concatString(@"_FOOT"); 8 // ========================
1 // ======================== 2 __block NSString* prefix_string = @"HEAD"; 3 NSString*(^concatString)(NSString* foot); 4 concatString = ^NSString *(NSString *foot){ 5 prefix_string = @"NEW_HEAD"; 6 return [prefix_string stringByAppendingString:foot]; 7 }; 8 concatString(@"_FOOT"); 9 // ========================
上面的代码说明什么情况下使用__block关键字。
在block内部使用非局部变量prefix_string时,如果不对prefix_string本身做修改的话,是不用加上__block关键字的。
如果要在block内部修改非局部变量,请务必加上__block。如果不加上,编译器也会报错的。
当一个非局部变量声明成了__block,在block体内操作这个非局部变量,对外面的这个非局部变量同样产生影响,改变它的值。
当没有使用__block定义非局部变量时,在block体中,就会产生一个非局部变量的副本,此时,block形成了闭包。
在block外对非局部变量操作时,不会影响block里面的值。
如果加了__block,此时对外部的非局部变量操作,会同时影响block内的变量值。
测试代码:
第一段代码输出是:
RED_FOOT RED
BLUE_FOOT BLUE
第二段代码输出是:
RED_FOOT RED
RED_FOOT BLUE
1 // ======================== 2 __block NSString* prefix_string = @"RED"; 3 NSString*(^concatString)(NSString* foot); 4 concatString = ^NSString *(NSString *foot){ 5 return [prefix_string stringByAppendingString:foot]; 6 }; 7 8 NSLog(@"%@ %@",concatString(@"_FOOT"), prefix_string); 9 prefix_string = @"BLUE"; 10 NSLog(@"%@ %@",concatString(@"_FOOT"), prefix_string); 11 12 // ========================
1 // ======================== 2 NSString* prefix_string = @"RED"; 3 NSString*(^concatString)(NSString* foot); 4 concatString = ^NSString *(NSString *foot){ 5 return [prefix_string stringByAppendingString:foot]; 6 }; 7 8 NSLog(@"%@ %@",concatString(@"_FOOT"), prefix_string); 9 prefix_string = @"BLUE"; 10 NSLog(@"%@ %@",concatString(@"_FOOT"), prefix_string); 11 // ========================
由上面可以很好的理解__block的作用,以及程序闭包,对upvalue(非block内部的局部变量)值的副本建立。
====================华丽丽的分割线=========================
总结:block将函数进行封装,并且可以通过传递block的引用的方式,大大的便利了程序的开发。
可以在程序的任意地方,使用block来完成回调处理事件。而block的闭包机制,也可以给block的安全性
带来极大的便利。不会因为外部对非局部变量的操作,引起block内部的错乱。block类似于函数指针,
对block的合理利用,很大程度上的提高程序的可读性。
相关文章推荐
- iOS开发笔记--iOS中的触摸事件和手势处理
- iOS中多线程的实现方案之pthread和NSThread
- 多线程基础知识介绍
- ios——1
- iOS开发笔记--iOS中的多线程
- iPhone/iOS开启个人热点的纵向适配小结
- iOS:quartz2D绘图(给图形绘制阴影)
- iOS学习之iOS沙盒(sandbox)机制和文件操作之NSFileManager(三)
- iOS:quartz2D绘图(绘制渐变图形)
- iOS学习之iOS沙盒(sandbox)机制和文件操作(二)
- iOS 中线程与进程的区别
- 定制一下最近一段时间的学习计划
- 【---重要---】 iOS:界面适配
- iOS系统后台运行机制研究
- iOS 7、iOS 8屏幕适配
- iOS开发中的字典转模型应用
- ios数据存储NSString,NSArray,NSDictionary
- iOS雨笙 NSTimer(计时器)和NSUserDefaults(最轻量级的持久化)的简单应用
- coreData 深入理解4 --总结 (线程安全与同步--iOS5 前后对比)
- iOS:quartz2D绘图(画一些简单的图形,如直线、三角形、圆、矩形、文字等)