iOS开发-Block回调

简介:

关于Block之前有一篇文章已经写过一篇文章Object-C-代码块Block回顾,不过写的比较浅显,不能体现出Block在实际开发中的重要性,关于Block的基础知识,可以参考之前的博客。在实际开发中Block在回调过程中的是非常适合开发使用,不管是苹果的官方的接口还是一些第三方库的接口中都用到了Block回调。很多情况下Block和GCD一起使用,最常见的场景的就是App去后台取数据的过程中是需要时间,数据取成功之后我们才能更新UI页面,这就是最常见的回调的方式,也可以通过Notification来做,如果是单个用Notification没问题,如果请求比较多的情况的,代码量会上一个级别。

Block回调

简单的Block写法,返回类型  Block名称  参数,基本上符合方法的写法,先看一个最简单的Block写法:

1
2
3
4
5
int   (^blockDemo)( int  a, int  b)=^( int  a, int  b){
     return  a+b;
};
 
NSLog (@ "BlockDemo的结果:%d" ,blockDemo(90,72));

最后的结果是162,简单明了,很容易看懂,现在我们先通过UITableView展示后台数据,效果如下:

ViewController中的代码,简单的实现了一下UITableView:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (UITableView *)tableView {
     if  (!_tableView) {
         _tableView = [[UITableView alloc]
                       initWithFrame:CGRectMake(0, 64, CGRectGetWidth( self .view.bounds) - 10,
                                                CGRectGetHeight( self .view.bounds) - 64)
                       style:UITableViewStylePlain];
         _tableView.rowHeight = 40.0;
         _tableView.sectionHeaderHeight = 0.0;
         _tableView.sectionFooterHeight = 0.0;
         _tableView.dataSource =  self ;
         _tableView.delegate =  self ;
     }
     return  _tableView;
}
 
-( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{
     return  [ self .dataSource count];
}
 
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath  *)indexPath{
     UITableViewCell  *cell=[[UITableViewCell alloc]init];
     cell.textLabel.text=[ self .dataSource objectAtIndex:indexPath.row];
     return  cell;
}

通过FEDataService中的fetchData取出数据:

1
2
3
4
-( NSMutableArray  *)fetchData{
     NSMutableArray   *mutableArray=[[ NSMutableArray  alloc]initWithObjects:@ "博客园" ,@ "FlyElephant" ,@ "http://www.cnblogs.com/xiaofeixiang" ,@ "iOS技术交流群:228407086" , nil ];
     return  mutableArray;
}

Controller中的调用:

1
2
self .dataService=[[FEDataService alloc]init];
self .dataSource=[ self .dataService  fetchData];

当时从后台取数据是需要时间的,而且网络不一定能取出数据,这个时候就可以通过Block进行回调,在DataService中重新定义了一个fetchDataSource方法:

1
-( void )fetchDataSource:( void (^)( NSMutableArray  *array, NSError  *error))fetchDataBlock;

注意这里的Block传参的写法,fetchDataBlock相当于是参数名,前面的是类型,实现中加入了GCD

1
2
3
4
5
6
7
8
-( void )fetchDataSource:( void  (^)( NSMutableArray  *,  NSError  *))fetchDataBlock{
     dispatch_time_t  time=dispatch_time(DISPATCH_TIME_NOW,  NSEC_PER_SEC *(int64_t)1.0);
     dispatch_after(time,dispatch_get_main_queue() , ^{
          NSMutableArray   *mutableArray=[[ NSMutableArray  alloc]initWithObjects:@ "博客园" ,@ "FlyElephant" ,@ "http://www.cnblogs.com/xiaofeixiang" ,@ "iOS技术交流群:228407086" , nil ];
         fetchDataBlock(mutableArray, nil );
     });
     
}

Controller中进行回调同样实现以上效果:

1
2
3
4
5
6
[ self .dataService fetchDataSource:^( NSMutableArray   *array, NSError  *error){
     if  (!error) {
         self .dataSource=array;
         [ self .tableView reloadData];
     }
}];

Block延伸

1.栈块,堆块和全局块

定义一个块的时候,其所占的内存区域是在栈中的,块只在定义它的那个范围有有效,我们可以先看一下下面的写法:

1
2
3
4
5
6
7
8
9
10
11
NSString   *string=@ "博客园FlyElephant" ;
void   (^block)();
if  ([string isEqualToString:@ "iOS技术交流群:228407086" ]) {
     block=^{
         NSLog (@ "keso" );
     };
} else {
     block=^{
         NSLog (@ "http://www.cnblogs.com/xiaofeixiang" );
     };
}

先定义了block,之后在判断语句中对block进行赋值,最终栈中保存两个块的内存,在判断语句之外调用block有可能会把分配给块的内存覆盖,最终造成的结果就是有的时候正确,被覆写的时候就会造成程序崩溃,解决上面问题的方式我们可以通过block从栈内存中通过copy存储在堆内存中,代码如下:

1
2
3
4
5
6
7
8
9
10
11
NSString   *string=@ "博客园FlyElephant" ;
void   (^block)();
if  ([string isEqualToString:@ "iOS技术交流群:228407086" ]) {
     block=[^{
         NSLog (@ "keso" );
     copy ];
} else {
     block=[^{
         NSLog (@ "http://www.cnblogs.com/xiaofeixiang" );
     copy ];
}

存储在堆中的块就变成了引用计算类型,当引用计数变成0在ARC的环境下的就会被系统回收,而栈中的内存是由系统自动回收的,所以第一段代码稳定性不能保证,还有一种是全局块,将全局块声明在全局内存中,编译期就已经确定,不需要每次用到的在栈中创建,全局块的拷贝是一个空操作,所以全局块不可能被系统回收。

2.通过typedef简化代码可读性

Block回调中我们发现传入一个块的对象写法有的时候看起来实在不是那么简单明了,我们可以通过typedef简化定义一个块:

1
typedef  void   (^FetchBlock)( NSMutableArray   *dataSouce, NSError   *error);

DataService中方法就可以简化了不少:

1
-( void )fetchDataSourceSimple:(FetchBlock)block;

实现代码和之前的block实现一样:

1
2
3
4
5
6
7
-( void )fetchDataSourceSimple:(FetchBlock)block{
     dispatch_time_t  time=dispatch_time(DISPATCH_TIME_NOW,  NSEC_PER_SEC *(int64_t)1.0);
     dispatch_after(time,dispatch_get_main_queue() , ^{
         NSMutableArray   *mutableArray=[[ NSMutableArray  alloc]initWithObjects:@ "博客园" ,@ "FlyElephant" ,@ "http://www.cnblogs.com/xiaofeixiang" ,@ "iOS技术交流群:228407086" nil ];
         block(mutableArray, nil );
     });
}

行笔匆匆,难免遗漏,如有不当,多多指教~

本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4666796.html,如需转载请自行联系原作者

相关文章
|
2月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
106 3
|
2月前
|
API 开发工具 Android开发
iOS 和 Android 平台的开发有哪些主要区别?
iOS与Android开发区别:iOS用Objective-C/Swift,App Store唯一下载渠道;Android用Java/Kotlin,多商店发布(如Google Play、华为市场)。设计上,iOS简洁一致,Android灵活可定制。开发工具,iOS用Xcode,Android用Android Studio。硬件和系统多样性,iOS统一,Android复杂。权限管理、审核流程及API各有特点,开发者需依据目标平台特性进行选择。
38 3
|
12天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
12天前
|
存储 Swift iOS开发
使用Swift开发一个简单的iOS应用的详细步骤。
使用Swift开发iOS应用的步骤包括:创建Xcode项目,设计界面(Storyboard或代码),定义数据模型,实现业务逻辑,连接界面和逻辑,处理数据存储(如Core Data),添加网络请求(必要时),调试与测试,根据测试结果优化改进,最后提交至App Store或其它平台发布。
32 0
|
12天前
|
安全 Swift iOS开发
【Swift 开发专栏】Swift 与 UIKit:构建 iOS 应用界面
【4月更文挑战第30天】本文探讨了Swift和UIKit在构建iOS应用界面的关键技术和实践方法。Swift的简洁语法、类型安全和高效编程模型,加上与UIKit的紧密集成,使开发者能便捷地创建用户界面。UIKit提供视图、控制器、布局、动画和事件处理等功能,支持灵活的界面设计。实践中,遵循设计原则,合理组织视图层次,运用布局和动画,以及实现响应式设计,能提升界面质量和用户体验。文章通过登录、列表和详情界面的实际案例展示了Swift与UIKit的结合应用。
|
12天前
|
存储 安全 Swift
【Swift 开发专栏】使用 Swift 开发一个简单的 iOS 应用
【4月更文挑战第30天】本文介绍了使用 Swift 开发简单 iOS 待办事项应用的步骤。首先,阐述了 iOS 开发的吸引力及 Swift 语言的优势。接着,详细说明了应用的需求和设计,包括添加、查看和删除待办事项的功能。开发步骤包括创建项目、界面搭建、数据存储、功能实现,并提供了相关代码示例。最后,强调了实际开发中需注意的细节和优化,旨在帮助初学者掌握 Swift 和 iOS 开发基础。
|
20天前
|
iOS开发 开发者 UED
利用SwiftUI构建动态列表:iOS开发的新范式
【4月更文挑战第22天】在本文中,我们将深入探讨如何使用SwiftUI来创建动态列表。SwiftUI是苹果最新推出的用户界面工具集,它允许开发者以声明式的方式描述用户界面,从而简化了代码的复杂性。我们将通过具体的代码实例,展示如何利用SwiftUI的List和ForEach视图来创建动态列表,并讨论其在实际开发中的应用。
20 2
|
24天前
|
API 定位技术 iOS开发
IOS开发基础知识:什么是 Cocoa Touch?它在 iOS 开发中的作用是什么?
【4月更文挑战第18天】**Cocoa Touch** 是iOS和Mac OS X应用的核心框架,包含面向对象库、运行时系统和触摸优化工具。它提供Mac验证的开发模式,强调触控接口和性能,涵盖3D图形、音频、网络及设备访问API,如相机和GPS。是构建高效iOS应用的基础,对开发者至关重要。
21 0
|
1月前
|
搜索推荐 iOS开发 开发者
利用SwiftUI构建动态用户界面:iOS开发新篇章
【4月更文挑战第10天】在移动应用的世界中,流畅的用户体验和引人注目的界面设计是至关重要的。随着SwiftUI的推出,iOS开发者被赋予了创造高度动态且响应式界面的能力。本文将深入探讨如何利用SwiftUI的强大特性来实现一个动态用户界面,包括其声明性语法、状态绑定以及视图更新机制。我们将通过一个天气应用案例,了解如何有效地运用这些工具来提升应用的交互性和视觉吸引力。
|
1月前
|
开发工具 Swift iOS开发
利用SwiftUI构建动态用户界面:iOS开发新范式
【4月更文挑战第3天】 随着苹果不断推进其软件开发工具的边界,SwiftUI作为一种新兴的编程框架,已经逐渐成为iOS开发者的新宠。不同于传统的UIKit,SwiftUI通过声明式语法和强大的功能组合,为创建动态且响应式的用户界面提供了一种更加简洁高效的方式。本文将深入探讨如何利用SwiftUI技术构建具有高度自定义能力和响应性的用户界面,并展示其在现代iOS应用开发中的优势和潜力。