iOS知识的学习总结--block回调函数

  在iOS开发中,block是很强悍的,也是我们必须掌握的,在此对block的回调做一个小结。

  首先简略地介绍一下block;Block的实际行为和Function很像,最大的差别是在可以存取同一个Scope的变量值。Block实体形式如下:

  ^(传入参数列){行为主体};

  Block实体开头是“^”,接着是由小括号所包起来的参数列(比如 int a, int b, int c),行为主体由大括号包起来,专有名字叫做block literal。行为主体可以用return回传值,类型会被compiler自动辨别。如果没有参数列要写成: ^(void)。

  PS:Block中的一个重要特性:内存释放。凡在block中使用的变量,block都将进行自动的释放。所以,如果使用系统全局变量作为参数传入block,一定在传入之前retain一次,才能保证这个变量不被release。如下:

复制代码
 1 //常见的几种block定义和使用
 2 
 3 - (void)viewDidLoad
 4 {
 5     [super viewDidLoad];
 6 
 7     //(1)定义无参无返回值的Block
 8     void (^printBlock)() = ^(){
 9         printf("no number");
10     };
11     printBlock();
12      
13     
14     int mutiplier = 7;
15     //(2)定义名为myBlock的代码块,返回值类型为int
16     int (^myBlock)(int) = ^(int num){
17         return num*mutiplier;
18     }
19     //使用定义的myBlock
20     int newMutiplier = myBlock(123);
21     NSLog(@"newMutiplier is %d",myBlock(123));
22 }
23 
24 
25 //定义在-viewDidLoad方法外部
26 //(3)定义一个有参数,没有返回值的Block
27 void (^printNumBlock)(int) = ^(int num){
28     NSLog(@"int number is %d",num);
29 };
复制代码

  这篇文章着重介绍一下我对block回调的理解与总结,回调函数可以从下面三个方面去理解:

  1、回调函数类似通知、委托

  2、回调函数声明、实现、回调可以在都一个类中,也可以把回调写到别的类中

  3、在A类中声明函数,在实现函数中,达到满足的条件,回调,在B类中的回调函数会被调用,并去处理满足条件的事情

  要想搞明白回调函数是怎么回事?那我们就要先想明白三个问题:

  1. 什么是回调函数?
  2. 使用回调函数有什么好处?
  3. 什么时候用回调函数?

第一个问题:什么是回调函数?

  由声明函数的类来调用的函数叫做回调函数。普通函数可以让任何类调用。谁回调?这个谁指的就是声明回调函数的那个类。

  回调函数,本质上也是个函数。它是由“声明”、“实现”、“调用”三部分组成。回调函数(其实是Block),它的的声明和调用在TestA类中,而实现部分在TestB类中。也就是说,TestB类实现了回调函数,但并没有权限调用,最终还是 由TestA类去进行调用的。我们称这样的机制为“回调”。简单地说就是:虽然函数的实现写在TestB类中,但是真正的调用还是得由TestA类来完成。而对比我们常用的正常函数函数来看,正常函数的声明、实现均在一个类中完成。下面写个小的例子来说明一下,示例代码如下:

复制代码
 1 TestA.h
 2 
 3 /**
 4  *  公司类
 5  */
 6 #import <Foundation/Foundation.h>
 7 
 8 @interface TestA : NSObject
 9 
10 /**
11  *  声明的回调函数:给指定的员工发工资
12  *
13  *  @param staffID 普通参数:员工ID
14  *  @param amount  回调函数:用来通知员工工资是多少
15  */
16 - (void)paySalaryForStaff:(int)staffID WithMoney:(void (^)(int salary))amount;
17 /*
18  在这个对象方法中(void (^) (int salary))是修饰回调函数amount的,这里(void (^)(int salary))就像是类型一样,这个amount是一个参数为salary的无返回值函数,用来告知员工工资多少
19  */
20 @end
复制代码
复制代码
 1 TestA.m
 2 
 3 #import "TestA.h"
 4 
 5 @implementation TestA
 6 
 7 /**
 8  *  <#Description#>
 9  *
10  *  @param staffID <#staffID description#>
11  *  @param amount  <#amount description#>
12  */
13 - (void)paySalaryForStaff:(int)staffID WithMoney:(void (^)(int salary))amount {
14 
15     //计算工资的多少
16     NSLog(@"工资5000,加班费25000,老大我很中意你,少年");
17     //计算完之后就触发回调函数,告诉员工发工资
18     amount(30000);
19 }
20 
21 @end
复制代码
复制代码
 1 TestB.h
 2 
 3 #import <Foundation/Foundation.h>
 4 
 5 /**
 6  *  员工类
 7  */
 8 @interface TestB : NSObject
 9 
10 /**
11  *  员工败家方法
12  */
13 - (void)spendMoney;
复制代码
复制代码
TestB.m

#import "TestB.h"
#import "TestA.h"

@implementation TestB

-(void)spendMoney {

    //各种无聊因为没有钱
    //傻X公司还不发工资
    //受不了了 我要问一下
    
    TestA *sbA = [[TestA alloc]init];
    
    //老子是007发工资了吗
    [sbA paySalaryForStaff:007 WithMoney:^(int salary) {//这个地方才是回调函数amount的实现
        
        //这里通过接收回调函数传的参数判断工资的多少
        if (salary == 30000) {
            
            NSLog(@"我去,加班费还阔以,出去嗨一哈");
            
            //各种嗨 钱不花完不回家
        }else {
        
            NSLog(@"公司不要脸,老纸要跳槽");
        }
    }];
}

@end
复制代码

  借用大牛的一个例子来理解“回调函数”概念:

  警局(类):

  招收一名警察甲(声明函数),并培养、训练他(实现函数)。

  招收一名卧底乙(声明函数),但并没有培养他,而是被送进了黑社会。但有任务的时候,警务处会调用卧底乙(回调函数)。

  黑社会(类):培养、训练卧底乙(实现函数)。

 

第二个问题:什么情况下使用回调函数?

假设有TestA、TestB两个类。

(1)TestA类有多种形态,要在TestB类中实现回调函数。如假设TestA类是网络请求开源类ASIHttpRequest,它可能请求成功,也可能请求失败。这个时候,TestB类就要针对以上两个情况,作不同的处理。

(2)TestA类的形态由TestB类决定时,要在TestB类中实现回调函数。如UITableView类就会提供很多回调函数(iOS专业术语称“委托”方法)

(3)TestA类需要向TestB类传递数据时,可以在TestB类中实现回调函数(A类一般是数据层比较耗时的操作类)。如举的那个发工资的例子。在实际编程中,这样的机制有个好处就是可以提升用户的操作体验。比如用户从X页面跳转到Y页面,需要向网络请求数据,而且比较耗时,那我们怎么办?有三种方案:第一种就是在X页面展示一个旋转指示器,当收到网络传回的数据时,在展现Y页面。第二种就是使用回调函数。用户从X页面直接跳转到Y页面,Y页面需要到数据让数据层去执行,当收到数据时,再在Y页面展现。第三种就是在Y页面中开启多线程。让一个子线程专门到后台去取数据。综合来说,第二种更加简介易懂,而且代码紧凑。

 

第三个问题:使用回调函数有什么好处?

(1)可以让实现方,根据回调方的多种形态进行不同的处理和操作,具体请参照ASIHttpRequest

(2)可以让实现方,根据自己的需要定制回调方的不同形态。

(3)可以将耗时的操作隐藏在回调方,不影响实现方其它信息的展示。

(4)让代码的逻辑更加集中,更加易读。

下次在对block做一个全面的分析学习。

posted @ 2016-03-08 00:19  愤怒的芒果丶  阅读(166)  评论(0)    收藏  举报
编辑推荐:
· C23和C++26的#embed嵌入资源指南
· 「EF Core」框架是如何识别实体类的属性和主键的
· 独立开发,这条路可行吗?
· 我在厂里搞 wine 的日子
· 如何通过向量化技术比较两段文本是否相似?
阅读排行:
· 推荐 5 款实用的 Docker 可视化管理工具,工作效率翻倍!
· 瞧瞧别人家的接口重试,那叫一个优雅!
· 【EF Core】框架是如何识别实体类的属性和主键的
· MySQL 13 为什么表数据删掉一半,表文件大小不变?
· 上周热点回顾(7.7-7.13)
点击右上角即可分享
微信分享提示