ios – 委托函数vs回调函数

前端之家收集整理的这篇文章主要介绍了ios – 委托函数vs回调函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
参见英文答案 > Problem understanding Delegating pattern & callback functions in Objective C3
我在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将自己添加为本地通知的观察者.

这不是一个“回调”本身,而是代表一个对象被通知完成一些异步任务的另一个模式.

这些是“回调”模式的几个例子.显然,所提供的例子是任意的和微不足道的,但希望它能给你一个你的选择的想法.现在最常用的两种技术是块和委托模式.当需要简单而优雅的界面时,块越来越受到青睐.但是对于丰富而复杂的界面,代表们很常见.

猜你在找的iOS相关文章