委托函数vs回调函数 [英] delegate function vs callback function

查看:143
本文介绍了委托函数vs回调函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



委托函数的示例是 numberOfRowsInSection UITableViewDelegate 协议和回调函数的例子是 didReceiveLocalNotification appDelegate.m

谢谢..

解决方案

有几个想法:


  1. 您建议 didReceiveLocationNotification 是一个回调函数,但它实际上只是一个委托方法 UIApplicationDelegate 协议。因此, numberOfRowsInSection didReceiveLocalNotification 都是简单的委托方法。



    当调度 NSTimer 或定义一个通用回调函数的句柄时,选择器 UIGestureRecognizer ,其中方法名称的选择未预先确定。



    或回调广泛用于 CFArray


  2. 但是,你的问题的根本不在术语上,而是一个如何定义一个接口的问题,调用者可以指定一个方法,其他对象将在以后的某个日期调用(异步)。有几种常见模式:




    • 阻止方法的参数 :常用于定义将块用作参数的方法。例如,你可以有一个定义如下的方法:

         - (NSURLSessionTask *)downloadAsynchronously :( NSURL *)url文件名:(NSString *)文件名completion:(void(^)(NSData * results,NSString * filename))完成{
      NSURLSessionTask * task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^ 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__);

      您会看到立即显示done消息,并且完成阻止将在下载完成后被调用。它确实需要一段时间才能习惯构成块变量/参数定义的标点符号的混乱,但是一旦你熟悉块语法,你会真的很感激这种模式。它消除了在调用某些方法和定义一些单独的回调函数之间的断开连接。



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

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

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

         - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)文件名完成(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;
      }


    • 委托协议模式 :对象之间通信的另一种常用技术是委托协议模式。首先,定义协议(回调接口的性质):

        @protocol DownloadDelegate< NSObject& 

      - (NSURLSessionTask *)didFinishedDownload:(NSData *)data filename:(NSString *)filename;

      @end

      然后,您定义将调用此类的类 DownloadDelegate 方法:

        @interface下载器:NSObject 
      b $ b @property(nonatomic,weak)id< DownloadDelegate>代表;

      - (instancetype)initWithDelegate:(id< DownloadDelegate>)delegate;
      - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSString *)filename;

      @end

      @implementation下载器

      - (instancetype)initWithDelegate:(id< DownloadDelegate>)委托{
      self = [ super init];
      if(self){
      _delegate = delegate;
      }
      return self; $ NS $ $

      $ b $(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];

      返回任务;
      }

      @end

      最后,控制器使用这个新的下载程序类必须符合 DownloadDelegate 协议:

        @interface ViewController()< DownloadDelegate> 

      @end

      并定义协议方法:

         - (void)didFinishedDownload:(NSData *)data filename:(NSString *)filename {
      NSLog ,[data length]);
      [data writeToFile:filename atomically:YES];
      }

      执行下载:

       下载器* downloader = [[Downloader alloc] initWithDelegate:self]; 
      [downloader downloadAsynchronously:url filename:filename];
      NSLog(@%s done,__FUNCTION__);


    • 选择器模式 :您看到的模式一些Cocoa对象(例如 NSTimer UIPanGestureRecognizer )是传递选择器作为参数的概念。例如,我们可以定义我们的下载器方法如下:

         - (NSURLSessionTask *)downloadAsynchronously :( NSURL *)url filename :(NSString *)filename target:(id)target selector:(SEL)selector {
      id __weak weakTarget = target; //使得dispatch_async不会保留选择器

      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 :) ];

      但是你还必须定义下载完成时将调用的单独方法: p>

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

      我个人认为这种模式太脆弱,依赖于协调接口无需编译器的任何帮助。


    • /developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Introduction.html\">通知:提供某种异步方法的结果的另一种机制是发送本地通知。当(a)网络请求的结果的潜在接收者在请求被启动时是未知的时,这通常是最有用的;或(b)可能有多个类想要被通知这个事件。因此,网络请求可以在其完成时发布特定名称的通知,并且任何有兴趣被通知该事件的对象可以通过 NSNotificationCenter



      这不是一个回调本身,但代表另一个模式,一个对象被告知完成一些异步任务。



的回调模式。显然,提供的示例是任意和微不足道的,但希望它应该给你一个想法你的替代品。现在最常见的两种技术是块和委托模式。当需要简单和优雅的接口时,越来越多地使用块。但对于丰富而复杂的界面,代表是很常见的。


I work on iOS platform , I want to know what is a delegate function and what is a callback function ? what is the difference between the two types of function or they are the same ??

example of delegate function is numberOfRowsInSection in UITableViewDelegate protocol and example of callback function is didReceiveLocalNotification in appDelegate.m

Can we create our own callback function in Objective-C , if YES ,give an example ...

Thank you..

解决方案

A couple of thoughts:

  1. You suggest that didReceiveLocationNotification was a "callback function", but it's actually just a delegate method of the UIApplicationDelegate protocol. So, both numberOfRowsInSection and didReceiveLocalNotification are simply delegate methods.

    Something more akin to a generic callback function would be the selector when scheduling a NSTimer or defining the handler for a UIGestureRecognizer, where the choice of method name is not predetermined.

    Or callbacks are used extensively in CFArray.

  2. But, the root of your question is less on the terminology, but rather a question of how to define an interface where the caller can specify a method that some other object will invoke (asynchronously) at some future date. There are a couple of common patterns:

    • Block parameter to method: It is increasingly common to define methods that take a block as a parameter. For example, you can have a method that is defined as follows:

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

      That third parameter, completion, is a block of code that will be called with the download is done. Thus, you can invoke that method as follows:

      [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__);
      

      You'll see that "done" message appear immediately, and that completion block will be called when the download is done. It admittedly takes a while to get used to the ungainly mess of punctuation that constitutes a block variable/parameter definition, but once you're familiar with the block syntax, you'll really appreciate this pattern. It eliminates the disconnect between the invoking of some method and the defining of some separate callback function.

      If you want to simplify the syntax of dealing with blocks as parameters, you can actually define a typedef for your completion block:

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

      And then the method declaration, itself, is simplified:

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

    • Delegate-protocol pattern: The other common technique for communicating between objects is the delegate-protocol pattern. First, you define the protocol (the nature of the "callback" interface):

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

      Then, you define your class that will be invoking this DownloadDelegate method:

      @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
      

      And finally, the original view controller which uses this new Downloader class must conform to the DownloadDelegate protocol:

      @interface ViewController () <DownloadDelegate>
      
      @end
      

      And define the protocol method:

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

      And perform the download:

      Downloader *downloader = [[Downloader alloc] initWithDelegate:self];
      [downloader downloadAsynchronously:url filename:filename];
      NSLog(@"%s done", __FUNCTION__);
      

    • Selector pattern: A pattern that you see in some Cocoa objects (e.g. NSTimer, UIPanGestureRecognizer) is the notion of passing a selector as a parameter. For example, we could have defined our downloader method as follows:

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

      You'd then invoke that as follows:

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

      But you also have to define that separate method that will be called when the download is done:

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

      Personally, I find this pattern to be far too fragile and dependent upon coordinating interfaces without any assistance from the compiler. But I include it for a bit of historical reference given that this pattern is used quite a bit in Cocoa's older classes.

    • Notifications: The other mechanism to provide the results of some asynchronous method is to send a local notification. This is generally most useful when either (a) the potential recipient of the results of the network request is unknown at the time the request was initiated; or (b) there may be multiple classes that want to be informed of this event. So the network request can post a notification of a particular name when it's done, and any object that is interested in being informed of this event can add themselves as an observer for that local notification through the NSNotificationCenter.

      This is not a "callback" per se, but does represent another pattern for an object to be informed of the completion of some asynchronous task.

Those are a few examples of "callback" patterns. Clearly, the example provided was arbitrary and trivial, but hopefully it should give you an idea of your alternatives. The two most common techniques, nowadays, are blocks and delegate patterns. Blocks are increasingly being preferred when a simple and elegant interface is needed. But for rich and complicated interfaces, delegates are very common.

这篇关于委托函数vs回调函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆