回调(callback)就是讲一段可执行的代码和一个特定的事件绑定起来。当特定的事件发生时,就会执行这段代码。Objective-C中四种途径可以实现回调:
- 目标-动作对(target-action):在程序开始等待前,要求“当事件发生时,向指定的对象发生某个特定的消息”。在这里接收消息的对象是目标(target),消息的选择器(selector)是动作(action)。
- 辅助对象(helper object):在程序开始等待前,要求“当事件发生时,向遵守相应协议的辅助对象发送消息”。委托对象(delegate)和数据源(data source)是常见的辅助对象。
- 通知(notification):即是通知中心(notification center)的对象。在程序开始等待前,可以告知通知中心“某个对象正在等待某些特定的通知。当其中的某个通知出现时,向指定的对象发送特定的消息”。当事件发生时,相关的对象会向通知中心发布通知,然后再由通知中心将通知转发给正在等待该通知的对象。
- Block对象(Blocks):Block是一段可执行的代码。在程序开始等待前,声明一个Block对象,当事件发生时,执行这段Block对象。
事例代码:
BNRLogger.h
#import <Foundation/Foundation.h>
@interface BNRLogger : NSObject <NSURLConnectionDelegate,NSURLConnectionDataDelegate>
{
NSMutableData *_incomingData;
}
@property (nonatomic) NSDate *lastTime;
-(NSString *) lastTimeString;
-(void)updateLastTime:(NSTimer *)t;
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
-(void)connectionDidFinishLoading:(NSURLConnection *)connection;
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
-(void)zoneChange:(NSNotification *)note;
@end
BNRLogger.m
#import "BNRLogger.h"
@implementation BNRLogger
-(NSString *)lastTimeString
{
static NSDateFormatter *dateFormatter = nil;
if (!dateFormatter) {
dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSLog(@"created dateFormatter");
}
return [dateFormatter stringFromDate:self.lastTime];
}
-(void) updateLastTime:(NSTimer *)t
{
NSDate *now = [NSDate date];
[self setLastTime:now];
NSLog(@"Just set time to %@", self.lastTimeString);
}
//三个协议
//收到一定字节数的数据后会被调用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"received %lu bytes",[data length]);
if (!_incomingData) {
_incomingData = [[NSMutableData alloc]init];
}
[_incomingData appendData:data];
}
//最后一部分数据处理完毕后会被调用
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"Got it all");
NSString *string = [[NSString alloc]initWithData:_incomingData encoding:NSUTF8StringEncoding];
_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]);
_incomingData = nil;
}
//通知
-(void)zoneChange:(NSNotification *)note
{
NSLog(@"The system time zone has changed!");
}
@end
main.m
#import <Foundation/Foundation.h>
#import "BNRLogger.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
// NSLog(@"Hello, World!");
BNRLogger *logger = [[BNRLogger alloc]init];
//将BNRLogger实例注册为观察者
[[NSNotificationCenter defaultCenter] addObserver:logger selector:@selector(zoneChange) name:NSSystemTimeZoneDidChangeNotification object:nil];
NSURL *url = [NSURL URLWithString:@"http://www.gutenberg.org/cacahe/epub/205/pg205.txt"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
__unused NSURLConnection *fetchConn = [[NSURLConnection alloc]initWithRequest:request delegate:logger startImmediately:YES];
//未使用变量,用于消除编译器警告
__unused NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:logger selector:@selector(updateLastTime:) userInfo:nil repeats:YES];
//运行循环
[[NSRunLoop currentRunLoop] run];
}
return 0;
}