回调函数是我们在编程中经常使用到的,但是很多新手只知道怎么用,不知其所以然。今天我们就来剖析下回调函数到底是个什么鬼。

先来看一个关于回调函数的形象的比喻

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件

再看下比较正式的定义

callback(回调)就是一段「代码」,我们会通过某种途径,将这段「代码」和一个特定的事件(event)联系起来,当特定事件(event)发生后,这段「代码」被执行。


好了,大家先不管能不能理解上面两种定义,先在脑袋里面有个印象。我们下面来通过实际的例子帮助大家理解回调函数的使用,然后在回头看看上面的定义,定会有拨开乌云见天日的感觉。

为什么要有「回调(callback)」

在这里,斗胆将程序分为两种:

  • 「非事件驱动」型程序
  • 「事件驱动(event-driven)」型程序

「非事件驱动」型程序。

这类程序,遵循这样一个流程:启动程序 -> 执行程序(代码) -> 退出程序。程序会在执行完所有代码后,立刻退出,中途不会有任何事件(event)发生(除非有bug)。

「事件驱动(event-driven)」型程序

这类程序,遵循这样一个流程:启动程序 -> 等待事件(event) -> 事件被触发 -> 执行callback(回调) -> 继续等待事件(event) -> 人为退出程序。

打个比方,我想用淘宝APP帮手机充值,一打开APP,它并不会马上跳到充值页面,是要等待我的点击事件,当点击了充值的按钮,才会跳到充值页面(执行了callback)。

所以,大家应该很容易联想到,iOS的应用几乎都是「事件驱动(event-driven)」的,应用一经启动,就在等待事件的发生,当发生某个事件(比如点击了某个按钮),应用就会执行某段代码(callback)进行响应。

这里的「事件(event)」,是非常宽泛的,可以是使用者的一次点击、可以是系统的一次通知、可以是服务器返回的一次数据、可以是蓝牙外设连接成功后,发送给手机的一条指令等等。


通过上面我们知道在事件驱动型的程序里面,我们需要当某一个特定条件被触发的时候去调用回调函数来执行某个动作。

下面我们来看看具体的例子。

实例1、数据更新触发回调

如下图所示:

在个人主页我们需要显示用户的昵称、头像、性别、签名,然后点击编辑按钮,跳转到编辑个人信息页面,编辑完个人信息之后,点击返回到主页的时候,我们需要根据用户设定的值来更新相应的信息。

个人主页

编辑用户信息

实现代码如下:

personalHomePage.m文件
**************************
- (void)editPersonalInfo{EditPersonalInfoController *edit = [[SGEditPersonalInfoController alloc]init];__weak typeof(self)weakself = self;edit.updateUserInfoBlock = ^(NSString *userName, NSString *userSex, NSString *userSign ,UIImage *userImage){weakself.userHeaderImageView.image = [userImage circleImage];//用户头像weakself.nickNameLabel.text = userName;//昵称weakself.signLabel.text = userSign;//签名weakself.sexImageView.image = ([userSex isEqualToString:@"女"]) ? [UIImage imageNamed:@"icon_female"] : [UIImage imageNamed:@"icon_male"];//性别}
}
EditPersonalInfoController.h文件
***********************************
@interface EditPersonalInfoController :UITableViewController
@property(nonatomic, copy)void(^updateUserInfoBlock)(NSString *userName, NSString *userSex, NSString *userSign ,UIImage *userImage) ;
@endEditPersonalInfoController.m文件
***********************************
- (void)personalInfoHadChanged{if (self.updateUserInfoBlock) {self.updateUserInfoBlock(self.userName, self.userSex, self.userSign, self.userImage);}
}

为了方便叙述,我们做如下规定:
personalHomePage类为A,EditPersonalInfoController为B

1、首先我们在A页面的editPersonalInfo方法里面跳转到B页面,在这个方法里面我们登记回调函数(block),这个回调函数的作用就是更新A页面的信息。

2、首先B页面需要申明回调函数,就是@property(nonatomic, copy)void(^updateUserInfoBlock)(NSString *userName, NSString *userSex, NSString *userSign ,UIImage *userImage) ;,然后B页面在个人信息被更改,这个时候触发了回调关联的事件,调用方法personalInfoHadChanged方法,在方法里面来调用回调函数,参数就是自己页面更改的信息。

3、一旦回调函数被调用,A页面就响应回调事件,作用就是根据B页面传递过来的参数更改A页面的各个控件的值。

    edit.updateUserInfoBlock = ^(NSString *userName, NSString *userSex, NSString *userSign ,UIImage *userImage){weakself.userHeaderImageView.image = [userImage circleImage];//用户头像weakself.nickNameLabel.text = userName;//昵称weakself.signLabel.text = userSign;//签名weakself.sexImageView.image = ([userSex isEqualToString:@"女"]) ? [UIImage imageNamed:@"icon_female"] : [UIImage imageNamed:@"icon_male"];//性别}

现在再回头把我在这三个步骤里面标记的红色字体部分和文章开头的比喻对照看下,是不是感觉有些明白了。我们再接再厉,多看几个例子,加深理解。

实例2、人为触发回调

除了实例1中提到的当特定的数据(页面数据,服务器返回数据等)被更改的时候需要触发回调函数做一些事情,还有一种情况也需要触发回调函数来做一些处理。

比如用户点击了某个按钮或者页面,我们需要做回调去处理一些逻辑。

具体来看一个实际场景:

如下图所示,是当网络无连接的时候显示的一个view,提示用户可以点击页面进行重新加载。

网络错误View

我们需要给该view添加一个Tap手势,当用户点击的时候我们就触发回调函数,让使用该viwe的控制器去重新加载数据。

代码实现:

NetworkErrorPromptView.h文件
**********************************
@interface NetworkErrorPromptView : UIView
@property(copy,nonatomic)void(^reloadBlock)();//申明回调函数
@endNetworkErrorPromptView.m文件
**********************************
@implementation NetworkErrorPromptView-(instancetype)initWithFrame:(CGRect)frame{if (self == [super initWithFrame:frame]) {self = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil] firstObject];[self addGestureRecognizer:[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(reload)]];}return self;
}-(void)reload{if (self.reloadBlock){self.reloadBlock();//调用回调函数}
}
@end

假设在一个UITableViewController里面使用了该view,使用懒加载初始化该view

-(NetworkErrorPromptView*)errorView{if (!_errorView) {_errorView = [[SGNetworkErrorPromptView alloc]init];_errorView.frame = CGRectMake(0, 0, self.tableView.w, self.tableView.h);__weak typeof(self) weakself = self;_errorView.reloadBlock = ^{//登记回调函数,被触发就调用[weakself.tableView.mj_header beginRefreshing];};}return _errorView;
}

PS:
实例1和实例2非常类似,只是触发回调函数的方式不一样而已,大家理解了实例1,实例2应该不难理解。
所以我就不再一步步的讲解,只是在使用和触发回调函数的地方做了注释


iOS的四种回调模式

其实在iOS里面有四种回调模式,具体如下图所示:

我们上面讲解的是使用block实现回调,因为block的语法看起来有些怪异,所以很多人刚开始使用block实现回调函数就容易出错。

其实block我们可以理解为简版的delegate模式,delegate模式我相信大家理解起来不困难吧,我们经常使用UITableViewController就有很多代理方法。

代理模式就是A页面在特定状态(我们上面说的实例1和2)委托B页面去做某一件事(触发回调函数)。

仔细想一下是不是就是block啊。

如果你不熟悉block的使用,完全可以使用delegate来代替block,用多了就理解回调函数了,然后你想用delegate还是block亦或是notification都可以。(notification少用,影响性能)


总结

我们知道如何使用回调函数,那么我们什么时候才需要用到回调函数呢?

结合上面的实例1和2,我们不难发现,以下场景需要使用回调函数。

如果我们的代码逻辑就是从上到下按顺序执行,中途不需要去做其他的逻辑,那就没必要使用回调函数了。

如果我们需要让只有当某一特定条件满足的时候(数据被更新,用户点击事件),我们才会去执行一段逻辑。这个时候我们就需要使用回调函数来实现了。


PS:
由于需要真机截图,自己的iPhone版本太高,xcode无法支持,所以无法截图。缺的图后续会补上,抱歉~~

转载于:https://www.cnblogs.com/XimuYouzi/p/5424522.html

Block实现iOS回调相关推荐

  1. cocos creator ios回调js代码传入中文参数出现乱码的解决

    ios原生端调用js代码.需要先将oc的字符串变量转为c++字符串或者字符指针.但是如果需要传值给js端的话,特别是中文的话,就会出现问题.oc转c++会用到utf8编码. 但是如果是中文的话,还需要 ...

  2. ios学习笔记block回调的应用(一个简单的例子)

    一.什么是Blocks       Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持,从ios4.0开始就很好的支持Block. 二 ...

  3. iOS开发-由浅至深学习block

    作者:Sindri的小巢(简书) 关于block 在iOS 4.0之后,block横空出世,它本身封装了一段代码并将这段代码当做变量,通过block()的方式进行回调.这不免让我们想到在C函数中,我们 ...

  4. iOS开发 - OC - block的详解 - 基础篇

    深入理解oc中的block 苹果在Mac OS X10.6 和iOS 4之后引入了block语法.这一举动对于许多OC使用者的编码风格改变很大.就我本人而言,感觉block用起来还是很爽的,但一直以来 ...

  5. 如何在 iOS 5 中使用 Block

    How To Use Blocks in iOS 5 Tutorial – Part 1 How To Use Blocks in iOS 5 Tutorial – Part 2 本人将示范项目放在了 ...

  6. IOS基础知识-ARC,分类,Block

    IOS基础知识-ARC,分类,Block ARC快速入门 本小节知识点: 1.ARC机制判断 2.ARC快速使用 ARC基本概念 本小节知识点: 1.什么是ARC 2.ARC的注意点和优点 3.ARC ...

  7. IOS block 教程

    2019独角兽企业重金招聘Python工程师标准>>> 本章学习目标: 1. 了解何谓block.  2. 了解block的使用方法. 注:变数=变量 Block 是iOS在4.0之 ...

  8. 有趣 IOS 开展 - block 使用具体解释

    Block 它是iOS于4.0新的程序语法之后,于iOS SDK 4.0之后,block应用几乎无处不在. 在其他语言中也有类似的概念,称为闭包(closure),实例object C兄弟swift ...

  9. iOS超全开源框架、项目和学习资料汇总(1)UI篇

    上下拉刷新控件 **1. ** MJRefresh --仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.(推荐) ...

最新文章

  1. Exchange与ADFS单点登录 PART 2:部署和配置ADFS
  2. 正则表达式——全部符号解释(详解)
  3. 后端传前端中文显示都是问好_前后端分离,后台返回的数据前端没法写,怎么办?...
  4. Oracle JDBC中的PreparedStatement占位符过多
  5. android中常见的回调模式
  6. 蓝桥杯第六届省赛JAVA真题----循环节长度
  7. 95-230-032-源码-WordCount走读-获取物理执行图
  8. 从Ibatis过渡到Mybatis-比较Mybaits较与Ibatis有哪些方面的改进
  9. Centos系统安装踩坑
  10. 不浪漫爱情--等你来--等你来
  11. java上下载的ex表格打不开怎么回事_Java 下载 Excel文件打不开
  12. 软件产品测试报告如何用于软件退税?
  13. 国产手机 不只是老罗一张嘴
  14. 合肥工业大学计算机保研,合肥工大(合肥工业大学保研去向)
  15. 部分设计模式案例代码
  16. iOS home键直接退出
  17. 致美网页练习完整代码
  18. Go语言基础(一篇上手go语言基本语法)
  19. 卫星伪距定位matlab,GPS卫星运动及定位matlab仿真.doc
  20. Kali2019安装ShuiZe|水泽-自动化信息收集工具安装

热门文章

  1. COM 学习(五)——编译、注册、调用
  2. SilverLight:布局(3)StackPanel 对象
  3. 使用jquery-qrcode生成二维码
  4. 简单的文本文件加密小程序
  5. 调制解调器报告了一个错误是什么状况
  6. 李开复曾说:“买车是一生最坏的投资”,真的是这样吗?对此你怎么看?
  7. 有人说,互联网电商把1000个实体店老板赚的钱,让10个互联网电商赚走了
  8. 从工作到创业迈开这一步很艰难吗
  9. 老程序员提给后浪程序员的职涯建议
  10. 为啥国内程序员写的代码也用英文注释?