热门标签 | 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


推荐阅读
  • 本文详细介绍了在 Vue.js 前端框架中集成 vue-i18n 插件以实现多语言支持的方法。通过具体的配置步骤和示例代码,帮助开发者快速掌握如何在项目中实现国际化功能,提升用户体验。同时,文章还探讨了常见的多语言切换问题及解决方案,为开发人员提供了实用的参考。 ... [详细]
  • 利用树莓派畅享落网电台音乐体验
    最近重新拾起了闲置已久的树莓派,这台小巧的开发板已经沉寂了半年多。上个月闲暇时间较多,我决定将其重新启用。恰逢落网电台进行了改版,回忆起之前在树莓派论坛上看到有人用它来播放豆瓣音乐,便萌生了同样的想法。通过一番调试,终于实现了在树莓派上流畅播放落网电台音乐的功能,带来了全新的音乐享受体验。 ... [详细]
  • 捕获并处理用户输入数字时的异常,提供详细的错误提示与指导
    在用户输入数字时,程序能够有效捕获并处理各种异常情况,如非法字符或格式错误,并提供详尽的错误提示和操作指导,确保用户能够准确输入有效的数字数据。通过这种方式,不仅提高了程序的健壮性和用户体验,还减少了因输入错误导致的系统故障。具体实现中,使用了Java的异常处理机制,结合Scanner类进行输入读取和验证,确保了输入的合法性和准确性。 ... [详细]
  • C++入门必备:首个博客知识点汇总
    本文总结了C++初学者需要掌握的关键知识点,特别强调了成员类型的区分。其中,protected成员与private成员在本类中的作用相同,但protected成员允许派生类的成员函数访问,而private成员则不允许。此外,文章还介绍了其他重要的C++基础概念,如类的构造函数、析构函数以及继承机制,为初学者提供了一个全面的学习指南。 ... [详细]
  • 本文全面解析了 gRPC 的基础知识与高级应用,从 helloworld.proto 文件入手,详细阐述了如何定义服务接口。例如,`Greeter` 服务中的 `SayHello` 方法,该方法在客户端和服务器端的消息交互中起到了关键作用。通过实例代码,读者可以深入了解 gRPC 的工作原理及其在实际项目中的应用。 ... [详细]
  • 在Python网络编程中,多线程技术的应用与优化是提升系统性能的关键。线程作为操作系统调度的基本单位,其主要功能是在进程内共享内存空间和资源,实现并行处理任务。当一个进程启动时,操作系统会为其分配内存空间,加载必要的资源和数据,并调度CPU进行执行。每个进程都拥有独立的地址空间,而线程则在此基础上进一步细化了任务的并行处理能力。通过合理设计和优化多线程程序,可以显著提高网络应用的响应速度和处理效率。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • 【Linux进阶指南】第一阶段第三课:体验与部署Ubuntu系统
    在正式踏上Linux学习之旅之前,本课程将引导你深入体验和部署Ubuntu系统。通过详细的操作步骤和实践演练,你将掌握Ubuntu的基本安装、配置及常用命令,为后续的进阶学习打下坚实的基础。此外,课程还将介绍如何解决常见问题和优化系统性能,帮助你更加高效地使用Ubuntu。 ... [详细]
  • 通过 NuGet 获取最新版本的 Rafy 框架及其详细文档
    为了帮助开发者更便捷地使用Rafy领域实体框架,我们已将最新版的Rafy框架程序集上传至nuget.org,并同步发布了最新版本的Rafy SDK至Visual Studio。此外,我们还提供了详尽的文档和示例,以确保开发者能够快速上手并充分利用该框架的强大功能。 ... [详细]
  • 1. 设置用户密码:使用 `slappasswd` 工具生成加密密码,确保账户安全。具体步骤如下:输入命令 `slappasswd -s NewPassword`,系统将提示重新输入新密码,并生成加密后的哈希值 {SSHA}xxxxxxxxxxxxxxxxx。2. 编写配置文件:编辑 `vildapus` 配置文件,添加必要的用户账户信息,以确保新用户能够顺利登录系统。 ... [详细]
  • 在学习LVM(逻辑卷管理)技术的过程中,我对MD(多设备)、DM(设备映射器)以及逻辑设备和RAID的实现有了深入的理解。LVM2架构主要由DM主模块及其多个子模块组成,其中linear子模块用于创建线性设备,类似于简单的磁盘分区拼接。此外,还探讨了其他子模块如striped、mirror等在提高性能和数据冗余方面的应用。通过实际操作,我掌握了LVM的基本配置和管理方法,能够灵活应对不同存储需求。 ... [详细]
  • 如何在CAD阅图软件中将PDF文件高效转换为CAD格式?
    如何在CAD阅图软件中将PDF文件高效转换为CAD格式? ... [详细]
  • VC维在机器学习中的应用与解析
    VC维在机器学习中的应用与解析VC维是指在机器学习中,一个假设空间能够正确分类的最大样本数量。具体而言,如果一个假设空间能够将N个样本以所有可能的 \(2^N\) 种方式完全分开,则称该假设空间具有N的VC维。VC维是衡量模型复杂度的重要指标,对于理解模型的泛化能力和过拟合风险具有重要意义。本文详细探讨了VC维的定义、计算方法及其在机器学习中的应用,并通过实例分析展示了其在模型选择和评估中的关键作用。 ... [详细]
  • 在使用Block时,正确的声明方法和确保线程安全是至关重要的。为了保证Block在堆中分配,应使用`copy`修饰符进行声明,因为栈中的Block与栈的生命周期绑定,容易导致内存问题。此外,还需注意Block捕获外部变量的行为,以避免潜在的循环引用和数据不一致问题。建议深入研究相关文档,以掌握更多高级技巧和最佳实践。 ... [详细]
  • 本文详细介绍了 Windows API 中的按钮控件及其应用实例。主要功能包括:1. `CheckDlgButton` 用于更改对话框中按钮的选中状态;2. `CheckRadioButton` 用于设置单选按钮的选中状态。此外,还探讨了按钮控件在实际开发中的多种应用场景,帮助开发者更好地理解和使用这些功能。 ... [详细]
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社区 版权所有