iOS开发-Block回调

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

Block回调

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

    int  (^blockDemo)(int a,int b)=^(int a,int b){
        return a+b;
    };

    NSLog(@"BlockDemo的结果:%d",blockDemo(90,72));

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

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

- (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取出数据:

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

Controller中的调用:

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

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

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

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

-(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中进行回调同样实现以上效果:

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

Block延伸

1.栈块,堆块和全局块

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

    NSString  *[email protected]"博客园FlyElephant";
    void  (^block)();
    if ([string isEqualToString:@"iOS技术交流群:228407086"]) {
        block=^{
            NSLog(@"keso");
        };
    }else{
        block=^{
            NSLog(@"http://www.cnblogs.com/xiaofeixiang");
        };
    }

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

    NSString  *[email protected]"博客园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简化定义一个块:

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

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

-(void)fetchDataSourceSimple:(FetchBlock)block;

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

-(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);
    });
}

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

时间: 2024-10-24 08:59:35

iOS开发-Block回调的相关文章

ios开发 Block(一) 代码块

一.什么是Blocks      Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持,从ios4.0开始就很好的支持Block. 二.在ios开发中,什么情况下使用Block      Block除了能够定义参数列表.返回类型外,还能够获取被定义时的词法范围内的状态(比如局部变量),并且在一定条件下(比如使用__block变量)能够修改这些状态.此外,这些可修改的状态在相同词法范围内的多个block之间是共享的,即便出了该词法范围

iOS开发——Block引起循环引用的解决方案

内存问题始终是软件开发中的头等大事,iOS开发中也不例外,在面试中也是必问的问题.今天我们主要来讲讲Block中涉及的循环引用问题.当我们自己一开始写代码的时候,可能会大量在block中使用self,但是当看到别人优秀的代码的时候,发现别人常常不是用self,而使用weakSelf. 为什么呢?本文的示例代码上传至 https://github.com/chenyufeng1991/Block_WeakSelf . 首先我先来说说内存管理的原则: 1.默认使用strong,可选weak.stro

ios开发 Block(二) 实现委托

委托和block是IOS上实现回调的两种机制.Block基本可以代替委托的功能,而且实现起来比较简洁,比较推荐能用block的地方不要用委托. 实现效果如图 第一步,自定义CustomCell 1 #import <Foundation/Foundation.h> 2 3 @interface CustomCell : UITableViewCell 4 5 @property (strong, nonatomic) IBOutlet UILabel *labName; 6 @property

iOS 简单易懂的 Block 回调使用和解析

老实说在早前我已经学会了如何使用 Block 来做一些方法回调,传递参数的功能,并且用 Block 简单封装了第三方的网络库(AFNetworking).虽说对 Block 的应用说不上得心应手,但是却是极其地喜欢使用这种设计模式,并且在项目中也大量地使用了. 但是,最近一位即将参加面试的学弟问我,什么是 Block 呢?我蒙圈了,但是毕竟是学长,我假装淡定地反问道:你所理解的 Block 是什么呢?学弟说:是一段封装的代码块,并可以放在任意位置使用,还可以传递数据.我心里暗喜,这孩子还是图样了

IOS开发block的使用

一个简单的block的定义: (void)(^myblock)()=^{ NSLog(@"------block输出----"); }; //调用blockmyblock(); 有参数和返回值的block (int)(^blockAdd)(int,int)=^(a,b){ return a+b; };//调用blockint sun = blockAdd(4,6); // 10 Block可以访问局部变量,但是默认情况下不能修该. 1如何传递一个block - (void)useWit

iOS开发 Block的用法

一:在ios,blocks是对象,它封装了一段代码,这段代码可以在任何时候执行.Blocks可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值.它和传统的函数指针很类似,但是有区别:blocks是inline运行时使用的,并且它对局部变量是只读的;而在c语言中函数指针是在编译时就运行. int (^myBlock)(int ,int) = ^(int a, int b){return a ;}; 等号左边表示block的定义 ,右边表示 block的实现体 左边 int 表示 返

IOS开发—block对外部变量的内存管理

block对外部变量的内存管理 代码块在ios中通常用于回调,本文主要介绍block对外部变量的管理机制.我们知道如果要在block中使用block外面的变量,如果该变量是局部变量,就要先将其申明为__block类型.为什么呢?这就涉及到block对外部变量的内存管理. 一.基本数据类型 先看下面测试代码: //局部变量 - (void)localDataTest { int localData = 100; NSLog(@"localData --%p",&localData

iOS开发Block的介绍以及Block的循环引用问题

1:block的循环引用问题最主要记住两点: 如果[block内部]使用[外部声明的强引用]访问[对象A], 那么[block内部]会自动产生一个[强引用]指向[对象A] 如果[block内部]使用[外部声明的弱引用]访问[对象A], 那么[block内部]会自动产生一个[弱引用]指向[对象A] 2: #import "ViewController.h" #import "XMGPerson.h" @interface ViewController () @prop

IOS开发-block的使用

这几天在在工程中总会用到block传值以及传方法,今天对block进行了整理. block代码块主要用于对象之间的通信(反向传值和方法传递). 首先,我们从内存管理方面来了解一下block block:我们称代码块,他类似一个方法.而每一个方法都是在被调用的时候从硬盘到内存,然后去执行,执行完就消失,所以,方法的内存不需要我们管理,也就是说,方法是在内存的栈区.所以,block不像OC中的类对象(在堆区),他也是在栈区的.如果我们使用block作为一个对象的属性,我们会使用关键字copy修饰他,