热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOS之Block

iOS中的Block机制,可以简化程序,实现回调功能。跟C语言中的函数指针类似。可以通过传递Block实现函数的回调处理。简单地例子:定义一个blockint(^myblock)(

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文件如下:

1 #import 
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 
 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之Block


推荐阅读
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
author-avatar
feixiang1563122
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有