委托函数与callback函数

我在iOS平台上工作,我想知道什么是委托函数,什么是callback函数? 这两种函数有什么区别或者它们是相同的?

委托函数的numberOfRowsInSectionUITableViewDelegate协议中的numberOfRowsInSection ,callback函数的示例是didReceiveLocalNotification中的appDelegate.m

我们可以在Objective-C中创build自己的callback函数,如果是,举个例子…

谢谢..

一些想法:

  1. 你build议didReceiveLocationNotification是一个“callback函数”,但它实际上只是UIApplicationDelegate协议的委托方法。 所以, numberOfRowsInSectiondidReceiveLocalNotification都是委托方法。

    更类似于通用callback函数的东西,当调度NSTimer或为UIGestureRecognizer定义处理程序时,select器的方法名称是没有预先确定的。

    或者在CFArray广泛使用callback。

  2. 但是,问题的根源不在于术语,而在于如何定义调用者可以指定某个其他对象将在某个未来date调用(asynchronous)的方法的接口的问题。 有一些常见的模式:

    • 将参数阻塞到方法 :定义以块为参数的方法越来越常见。 例如,你可以有一个定义如下的方法:

       - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)filename completion:(void (^)(NSData *results, NSString *filename))completion { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ completion(data, filename); }); }]; [task resume]; return task; } 

      第三个参数,即completion ,是一个将在下载完成时调用的代码块。 因此,您可以按如下方式调用该方法:

       [self downloadAsynchronously:url filename:filename completion:^(NSData *results, NSString *filename) { NSLog(@"Downloaded %d bytes", [results length]); [results writeToFile:filename atomically:YES]; }]; NSLog(@"%s done", __FUNCTION__); 

      你会看到“完成”消息立即出现,并且completion块将在下载完成时被调用。 无可否认,它需要一段时间才能适应构成块variables/参数定义的标点符号,但是一旦熟悉了块语法,您将会非常欣赏这种模式。 它消除了调用某个方法和定义一些单独的callback函数之间的断开。

      如果你想简化处理块的语法作为参数,你实际上可以为你的完成块定义一个typedef

       typedef void (^DownloadCompletionBlock)(NSData *results, NSString *filename); 

      然后,方法声明本身就被简化了:

       - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)filename completion:(DownloadCompletionBlock)completion { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ completion(data, filename); }); }]; [task resume]; return task; } 
    • 委托协议模式 :对象之间通信的另一种常用技术是委托协议模式。 首先,定义协议(“callback”接口的性质):

       @protocol DownloadDelegate <NSObject> - (NSURLSessionTask *)didFinishedDownload:(NSData *)data filename:(NSString *)filename; @end 

      然后,你定义你的类将调用这个DownloadDelegate方法:

       @interface Downloader : NSObject @property (nonatomic, weak) id<DownloadDelegate> delegate; - (instancetype)initWithDelegate:(id<DownloadDelegate>)delegate; - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)filename; @end @implementation Downloader - (instancetype)initWithDelegate:(id<DownloadDelegate>)delegate { self = [super init]; if (self) { _delegate = delegate; } return self; } - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)filename { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate didFinishedDownload:data filename:filename]; }); }]; [task resume]; return task; } @end 

      最后,使用这个新的Downloader类的原始视图控制器必须符合DownloadDelegate协议:

       @interface ViewController () <DownloadDelegate> @end 

      并定义协议方法:

       - (void)didFinishedDownload:(NSData *)data filename:(NSString *)filename { NSLog(@"Downloaded %d bytes", [data length]); [data writeToFile:filename atomically:YES]; } 

      并执行下载:

       Downloader *downloader = [[Downloader alloc] initWithDelegate:self]; [downloader downloadAsynchronously:url filename:filename]; NSLog(@"%s done", __FUNCTION__); 
    • select器模式 :在某些Cocoa对象(例如NSTimerUIPanGestureRecognizer )中看到的模式是将select器作为parameter passing的概念。 例如,我们可以定义我们的下载器方法如下:

       - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)filename target:(id)target selector:(SEL)selector { id __weak weakTarget = target; // so that the dispatch_async won't retain the selector NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [weakTarget performSelector:selector withObject:data withObject:filename]; #pragma clang diagnostic pop }); }]; [task resume]; return task; } 

      然后你可以如下调用它:

       [self downloadAsynchronously:url filename:filename target:self selector:@selector(didFinishedDownload:filename:)]; 

      但是,您还必须定义下载完成后将调用的单独方法:

       - (void)didFinishedDownload:(NSData *)data filename:(NSString *)filename { NSLog(@"Downloaded %d bytes", [data length]); [data writeToFile:filename atomically:YES]; } 

      就我个人而言,我觉得这个模式太脆弱了,依赖于协调接口而没有编译器的帮助。 但是我把它包含在一些历史参考中,因为这种模式在cocoa的老一类中使用得相当多。

    • 通知 :提供某种asynchronous方法的结果的其他机制是发送本地通知。 当(a)networking请求的结果的潜在接收者在发起请求时是未知的时,这通常是最有用的; 或者(b)可能有多个类想要被告知这个事件。 因此,networking请求可以在完成时发布特定名称的通知,并且任何感兴趣被告知该事件的对象都可以通过NSNotificationCenter将自己添加为该本地通知的观察者。

      这本身并不是一个“callback” 但它代表了另一个模式,以便通知某个对象完成某个asynchronous任务。

这些是“callback”模式的几个例子。 显然,所提供的例子是任意的和微不足道的,但希望它能给你一个你的select的想法。 现在最常用的两种技术是块和委托模式。 当需要简单而优雅的界面时,块越来越受到欢迎。 但是对于丰富而复杂的界面,代表非常普遍。