服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - iOS中Block的回调使用和解析详解

iOS中Block的回调使用和解析详解

2021-01-31 19:51纯洁的小袋子 IOS

刚刚进入iOS开发行业,发现开发中要用到大量的block回调,由此可见它的重要性。本文主要讲的是 Block 回调的使用,以及 Block 是如何实现这种神奇的回调两部分来讲的,下面来一起看看吧。

block 回调实现

先跟着我实现最简单的 block 回调传参的使用,如果你能举一反三,基本上可以满足了 oc 中的开发需求。已经实现的同学可以跳到下一节。

首先解释一下我们例子要实现什么功能(其实是烂大街又最形象的例子):

有两个视图控制器 a 和 b,现在点击 a 上的按钮跳转到视图 b ,并在 b 中的textfield 输入字符串,点击 b 中的跳转按钮跳转回 a ,并将之前输入的字符串

显示在 a 中的 label 上。也就是说 a 视图中需要回调 b 视图中的数据。

想不明白的同学可以看一看最终实现的效果图:

iOS中Block的回调使用和解析详解

这里不再对 block 的语法做说明了。

首先,我们需要定义两个试图控制器 aviewcontroller bviewcontroller,现在我们需要思考一下,block 应该在哪里定义呢?

我们可以简单地这样思考,需要回调数据的是 a 视图,那么 block 就应该在 b 中定义,用于获取传入回调数据。

因此我们在 bviewcontroller.h 中定义如下:

?
1
2
3
4
5
6
7
8
9
//bviewcontroller.h
#import <uikit/uikit.h>
 
typedef void(^callbackblcok) (nsstring *text);//1
 
@interface bviewcontroller : uiviewcontroller
 
@property (nonatomic,copy)callbackblcok callbackblock;//2
@end

在这里,代码 1 用 typedef 定义了 void(^) (nsstring *text)的别名为 callbackblcok 。这样我们就可以在代码 2 中,使用这个别名定义一个 block 类型的变量 callbackblock

在定义了 callbackblock 之后,我们可以在 b 中的点击事件中添加 callbackblock 的传参操作:

?
1
2
3
4
5
6
//bviewcontroller.m
 
- (ibaction)click:(id)sender {
 self.callbackblock(_textfield.text); //1
 [self.navigationcontroller poptorootviewcontrolleranimated:yes];
}

这样我们就可以在想要获取数据回调的地方,也就 a 的视图中调用 block:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
// aviewcontroller.m
- (ibaction)push:(id)sender {
 bviewcontroller *bvc = [self.storyboard instantiateviewcontrollerwithidentifier:@"bviewcontroller"];
 
 bvc.callbackblock = ^(nsstring *text){ // 1
 
  nslog(@"text is %@",text);
 
  self.label.text = text;
 
 };
 [self.navigationcontroller pushviewcontroller:bvc animated:yes];
}

代码 1 中,通过对回调将 b 中的数据传递到代码块中,并赋值给 a中的 label,实现了整个回调过程。

上例是通过将 block 直接赋值给 block 属性,也可以通过方法参数的方式传递 block 块。

关于 block 的疑惑

到目前为止,一切看起来都很美好(如果你照着上面的例子做的话),功能正常, a 视图中也获取到数据了。但是某些人可能就要说了,你的代码有问题,你的思路有问题,你这是误人子弟。

是的,代码的确还有问题,第一个问题就是循环引用的问题,在 a 视图的block 代码块中:

?
1
2
3
4
bvc.callbackblock = ^(nsstring *text){
  nslog(@"text is %@",text); 
  self.label.text = text; 
 };

代码 self.label.text = text; ,在 block 中引用 self ,也就是 a ,而 a 创建并引用了 b ,而 b 引用 callbackblock,此时就形成了一个循环引用,而编译器也不会报任何错误,我们需要非常小心这个问题(面试百分百问到我会乱说?)。此时我们通常的解决方法是使用弱引用来解除这个循环:

?
1
2
3
4
5
6
__weak aviewcontroller *weakself = self;
 bvc.callbackblock = ^(nsstring *text){
  nslog(@"text is %@",text);
//  self.label.text = text;
  weakself.label.text = text;
 };

第二个问题是我自己对 block 的理解不到位,我们都知道 block 能截取自动变量,并且是不能在 block 块中进行修改的(除非用__block修饰符),但是很明显 weakself.label.text的值被修改了,并且没有用__block修饰符, 这是为什么呢?因为 label 是个全局变量,而如果像如下的局部变量 a 是不能修改的,编译器也会报错:

iOS中Block的回调使用和解析详解
局部变量

通过这个小例子发现的两个问题,也算是值得了。

block 为什么能实现神奇的回调

在这里我不会说什么实现原理,仅仅是个人对 block 能实现神奇回调的理解,有错误的地方请大家指出。

在先前使用 block 的过程中,虽然会使用,但是总是有一个疑惑,简单说来就是:

为什么在 a 中的 block 块能调用到 b 中的数据?

回顾一下我们在 b 中所实现的代码,不外乎定义了一个 block 变量,并在适当的时候传入参数,那么为什么在调用了  self.callbackblock(_textfield.text) 之后,值就神奇传到了 a 中的 block 块了呢?

通过整理使用的过程,我发现是我们的思维陷入了误区(可能是我个人),我们认为在 b 中传入 _textfield.text 参数之后, a 中的 block 块就可以获取到值。虽然思路是对的,但其实是不完整,导致我们形成了回调的数据是通过某种底层实现传递过去的错觉,这就使得我们认为这不需要深究。

事实是,通过简单的整理我们可以发现完整的回调流程应该是这样的:

iOS中Block的回调使用和解析详解
回调流程

block 代码块赋值给 bvc.callbackblock,此时 callbackblock 的指针就指向这个代码块。

调用 callbackblock(nsstring *text)

由于 callbackblock 的指针是指向 a 中的 block 代码块,因此执行代码块的代码,实现回调。

很显然之前我忽略了代码块赋值给 callbackblock 的这个操作(羞愧)。

现在再通过一段代码可以更清晰地理解这个原理:

?
1
2
3
4
5
6
bvc.callbackblock = ^(nsstring *text){ //1
 nslog(@"text is %@",text);
};
bvc.callbackblock = ^(nsstring *text){ //2
 nslog(@"text b is %@",text);
};

上述代码中,我们对 callbackblock进行了两次赋值,结果会怎么样呢?

iOS中Block的回调使用和解析详解
two block

可以看出来,block 的回调只对代码 2 生效,因为callbackblock的指针最后指向了代码 2 的代码块。所以并没有什么神奇的魔法,也没什么隐藏的底层机制(这里指的是方便理解的底层)让你可以带着疑惑去使用它。

总结

我这个人学习方法,总结起来就是看到新技术,先在自己的代码里跑一遍,能跑通,并且使用起来没有什么难度,就基本不会深究了。但是自我反思过,这样的学习方法是很不对的,写代码不能不求甚解,如果想要有所突破,不想局限于码农,一定要深入探究一下实现的机制,最起码要保证不带着疑惑去使用。以上就是这篇文章的全部内容,希望能对大家的学习或者工作带来一定的帮助,如果有疑问大家可以留言交流。

延伸 · 阅读

精彩推荐
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28