iOS学习笔记之回调(二)

写在前面

上一篇学习笔记中简单介绍了通过目标-动作对实现回调操作:创建两个对象timer和logger,将logger设置为timer的目标,timer定时调用logger的sayOuch函数。在这个例子中,timer的任务比较简单,只完成一项任务:在指定的时刻触发事件。在这种情况下,适合选择目标-动作来实现回调,但这种方式不适合要发送多个回调的情况。

辅助对象

辅助对象是另一种实现回调的方式。在应用开始等待前,要求当等待的特定事件发生时,向遵守相应协议的辅助对象发送消息。委托对象数据源是常见的辅助对象。

案例

假定我们创建一个NSURLConnection对象并从一个给定的url中获取数据,然后等待回调。回调函数被触发的时机包括:获得数据、数据获取完成、获取数据失败等。
可见,如果只是简单的目标-动作队机制,无法实现这些复杂的回调。因此,我们为NSURLConnection对象设置一个辅助对象,这个辅助对象专门负责处理特定事件发生之后的事情,也就是说,当特定的事件发生后,NSURLConnection对象会向辅助对象发送消息。这些消息包含在一套协议中。协议和接口概念有些相似,协议就是一组方法的声明,遵循相应协议的类必须实现协议中的方法(可以只实现部分方法)。
我们假定让Logger类型的对象成为NSURLConnection对象的辅助对象,也就是说,将Logger对象赋给NSURLConne对象的成员变量delegate。Logger类必须实现NSURLConnection协议中的部分活全部方法。关系图如下:

首先更改Logger类的代码,由于要接收数据,因此为Logger类添加一个NSMutableData类型的属性,如下:
Logger.h

@property NSMutableData *incomingData;

然后在Logger.m中实现协议中的部分方法

//收到一定字节数的数据后会被调用
- (void)connection:(NSURLConnection *)connection
    didReceiveData:(NSData *)data
{
    NSLog(@"received %lu bytes", [data length]);

    if (!self.incomingData) {
        self.incomingData = [[NSMutableData alloc] init];
    }

    [self.incomingData appendData: data];
}

//最后一部分数据处理完毕后,会被调用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Got it all!");

    NSString *string = [[NSString alloc] initWithData:self.incomingData
                                             encoding:NSUTF8StringEncoding];
    self.incomingData = nil;
    NSLog(@"string has %lu characters", [string length]);

    NSLog(@"The whole string is %@", string);
}

//获取数据失败时,会被调用
- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error
{
    NSLog(@"connection failed: %@",[error localizedDescription]);
    self.incomingData = nil;
}

在main函数中创建Logger对象和NSURLConnection,并将前者设置为后者的辅助对象:

Logger *logger = [[Logger alloc] init];

        NSURL *url = [NSURL URLWithString:@"http://www.cnblogs.com/scut-linmaojiang/p/iOS-huidiao-y.html"];

        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSURLConnection *fetchConn = [[NSURLConnection alloc]
                                               initWithRequest:request
                                                      delegate:logger
                                              startImmediately:YES];

如上所示,当NSURLConnection对象fetchConn从指定url获取数据时,将logger对象设置为它的辅助对象,也就是将logger作为fetchConn对象的委托。fetchCon获取数据过程中的各种状态会触发logger执行对应状态下的方法。利用断点设置,我们可以知道正常情况下,logger执行回调函数的顺序为:
1、接收到数据,执行

- (void)connection:(NSURLConnection *)connection
    didReceiveData:(NSData *)data

运行截图如下:

2、最后一部分数据处理完毕,执行

- (void)connectionDidFinishLoading:(NSURLConnection *)connection

运行截图如下:

...

url是上一篇笔记的地址,获取到的数据是以html格式显示的

如果计算机处理断网状态,那么fetchConn将无法获取到数据,此时logger将执行下面的回调函数

- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error

运行截图如下:

总结

对比目标-动作对机制和辅助对象机制这两种实现回调的方式可知,当某个对象只提供了一个回调函数时,使用目标-动作对较为合适。而当某个对象要提供多个回调函数,也就说要接收多个回调信息时,使用遵循相应协议的辅助对象较为合理。

时间: 2024-10-23 17:44:25

iOS学习笔记之回调(二)的相关文章

iOS学习笔记13-网络(二)NSURLSession

在2013年WWDC上苹果揭开了NSURLSession的面纱,将它作为NSURLConnection的继任者.现在使用最广泛的第三方网络框架:AFNetworking.SDWebImage等等都使用了NSURLSession.作为iOS开发人员,应该紧随苹果的步伐,不断的学习,无论是软件的更新.系统的更新.API的更新,而不能墨守成规. 相比较NSURLConnection,NSURLSession提供了 配置会话缓存.协议.cookie和证书能力,这使得网络架构和应用程序可以独立工作.互不干

iOS学习笔记20-地图(二)MapKit框架

一.地图开发介绍 从iOS6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的. 在iOS中进行地图开发主要有三种方式: 利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制 调用苹果官方自带的地图应用,主要用于一些简单的地图应用,无法精确控制 使用第三方地图开发SDK库 用得最多的还是MapKit,所以这节就只讲MapKit的使用. 二.MapKit核心类 MapKit的核心类为地图展示控件MKMapView,以下是常用的属性.对象方法以及

ios学习笔记block回调的应用(一个简单的例子)

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

iOS学习笔记16-数据库SQLite

一.数据库 在项目开发中,通常都需要对数据进行离线缓存的处理,如新闻数据的离线缓存等.离线缓存一般都是把数据保存到项目的沙盒中.有以下几种方式: 1. 归档:NSKeyedArchiver 2. 偏好设置:NSUserDefaults 3. plist存储:writeToFile 上述的使用可以参考iOS学习笔记15-序列化.偏好设置和归档,但上述三种方法都有一个致命的缺点,那就是都无法存储大批量的数据,有性能的问题,在这个时候就是使用数据库的时候. 数据库(Database)是按照数据结构来组

iOS学习笔记---c语言第十一天

函数指针 一.函数指针定义 //函数声明:声明我是一个什么函数 //求两个数的和 //函数的类型:int (int x,int y) //即:我是一个返回值为整型,有两个整型参数的函数. //函数名是 sum int sum(int x,int y); 函数指针定义p是变量,其他是类型(通常没有形参a,b) //函数指针类型 int (*)(int x,int y) //描述:指向 返回值为 int 两个int参数 的 指针类型 //函数指针变量: p //初始值 : sum printf("%

IOS学习笔记 -- Modal和Quartz2D

一. Modal1.Modal的默认效果:新控制器从屏幕的最底部往上钻,直到盖住之前的控制器为止;Modal只是改变了View的现实,没有改变rootViewController 2.常用方法1>.以Modal的形式展示控制器- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion2>.关

iOS学习笔记(2)— UIView用户事件响应

iOS学习笔记(2)— UIView用户事件响应 UIView除了负责展示内容给用户外还负责响应用户事件.本章主要介绍UIView用户交互相关的属性和方法. 1.交互相关的属性 userInteractionEnabled 默认是YES ,如果设置为NO则不响应用户事件,并且把当前控件从事件队列中删除.也就是说设置了userInterfaceEnabled属性的视图会打断响应者链导致该view的subview都无法响应事件. multipleTouchEnabled  默认是NO,如果设置为YE

iOS学习笔记(3)— 屏幕旋转

iOS学习笔记(3)— 屏幕旋转 一.屏幕旋转机制: iOS通过加速计判断当前的设备方向和屏幕旋转.当加速计检测到方向变化的时候,屏幕旋转的流程如下: 1.设备旋转时,系统接收到旋转事件. 2.系统将旋转事件通过AppDelegate通知当前的主Window. 3.window通知它的rootViewController. 4.rootViewController判断所支持的旋转方向,完成旋转. iOS系统中屏幕旋转事件没有像触碰事件那样进行hitTest,所以只有rootViewControl

iOS学习笔记-精华整理

iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始等待用户的操作,自动释放池就会被释放掉(调用dealloc),池中的对象都会收到一个release,有可能会因此被销毁. 2-成员属性:     readonly:不指定readonly,默认合成getter和setter方法.外界毫不关心的成员,则不要设置任何属性,这样封装能增加代码的独立性和安全