我在iOS平台上工作,我想知道什么是代理功能,什么是回调函数?两种功能的区别是什么?
代理函数的例子是UITableViewDelegate协议中的numberOfRowsInSection和回调函数的示例是appDelegate.m中的didReceiveLocalNotification
我们可以在Objective-C中创建自己的回调函数,如果是,给出一个例子…
谢谢..
解决方法
>你建议didReceiveLocationNotification
是一个“回调函数”,但它实际上只是UIApplicationDelegate协议的委托方法.所以,numberOfRowsInSection和didReceiveLocalNotification都是简单的委托方法.
与调用NSTimer或定义UIGestureRecognizer的处理程序相比,类似于通用回调函数的选择器将是选择器,其中方法名称的选择不是预先确定的.
或者回调在CFArray
被广泛使用.
>但是,您的问题的根源不在于术语,而是一个如何定义一个接口的问题,其中调用者可以指定某个其他对象将来某个日期将异步地调用(异步)的方法.有几种常见的模式:
> Block parameter to method:定义以块为参数的方法越来越常见.例如,您可以使用如下定义的方法:
- (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; }
第三个参数,完成,是一个代码块,将被下载完成.因此,您可以如下调用该方法:
[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__);
您将看到“完成”消息立即显示,并且完成该块将在下载完成时被调用.它确实需要一段时间才能习惯于构成块变量/参数定义的标点符号,但是一旦你熟悉了这个块语法,你就会很欣赏这个模式.它消除了调用某些方法和定义一些单独的回调函数之间的断开连接.
如果要简化处理块作为参数的语法,您可以实际为您的完成块定义一个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,filename); }); }]; [task resume]; return task; }
> Delegate-protocol pattern:对象之间通信的另一种常用技术是委托协议模式.首先,您定义协议(“回调”接口的性质):
@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,^{ [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__);
> Selector pattern:您在某些Cocoa对象(例如NSTimer,UIPanGestureRecognizer)中看到的模式是将选择器作为参数传递的概念.例如,我们可以定义我们的下载方法如下:
- (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,^{ #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的老版本中使用相当多,所以我将其包含在一些历史参考中.
> Notifications:提供一些异步方法的其他机制是发送本地通知.当(a)网络请求的结果的潜在接收者在请求启动时是未知的,这通常是最有用的;或(b)可能会有多个类别希望被通知此事件.因此,网络请求可以在完成后发布特定名称的通知,并且任何有兴趣被通知此事件的对象可以通过NSNotificationCenter将自己添加为本地通知的观察者.
这不是一个“回调”本身,而是代表一个对象被通知完成一些异步任务的另一个模式.
这些是“回调”模式的几个例子.显然,所提供的例子是任意的和微不足道的,但希望它能给你一个你的选择的想法.现在最常用的两种技术是块和委托模式.当需要简单而优雅的界面时,块越来越受到青睐.但是对于丰富而复杂的界面,代表们很常见.