Objective-C:如何将完成块提供给使用方法执行结果的方法

Objective-C: How to give a completion block to a method that uses a result from the method execution

对象 X 需要下载图像。它有 URL 个图像(可以是网络文件)。我有一个通用的 imageHandler class 可以接受 URL 并获取 imageData。我想要这个方法,能够使用完成块来自定义如何处理下载的图像。

我很熟悉如何使用委托模式来做到这一点。例如

@protocol ImageHandler: NSObject
-(void) getImageFromURL:(NSURL *)url forDelegate:(id <ImageRequestor>)delegate;
@end

@protocol ImageRequestor: NSObject
-(void) image:(UIImage *) image RetrievedForURL:(NSURL *)url withError:(NSError *)error;
@end

所以,基本上 objectX class getImageFromURL:delegate 方法以委托作为自身。符合ImageRequestor协议。

ImageHandler 对象,存储 url 以在散列 table 中委托映射。完成后,在委托上调用 image:RetrievedForURL:withError:。在这种方法中,我对图像和错误进行操作。

如何使用将 "what i want to do with the retrieved image" 作为一段代码传递的完成块实现相同的效果。

我看到的一种方法如下。但看起来它需要 ImageHandler 方法实现调用带有特定参数的完成。这是实现它的公认方法吗(即完成处理程序依赖于接收它的方法以使用正确的参数调用它)?

@protocol ImageHandler: NSObject
-(void) getImageFromURL:(NSURL *)url withCompletionHandler:(void (^)(UIImage *image, NSError * err))completionBlock;
@end

getImageFromURL:(NSURL *)url withCompletionHandler:(void (^)(UIImage *image, NSError * err))completionBlock 的实现看起来像

getImageFromURL:(NSURL *)url withCompletionHandler:(void (^)(UIImage *image, NSError * err))completionBlock
{
 //Get UIImage from URL, store it UIIMage ObjectX
 //if error happens, store it in NSError objectY, else it is nil
 //call completion handler 
 completionBlock(<UIIMage objectX>,<NSError objectY>);
}

是的,您展示的是执行此操作的典型方法。查看 Apple 自己的 API,发现它们以相同的方式进行操作。例如-[NSURLSession dataTaskWithURL:completionHandler:],其声明为:

- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url 
                        completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

在您的 ImageRequestor.h 文件中写入以下内容:

#import <Foundation/Foundation.h>

// Here you define your custom response block with the desired parameters
// That in this case are UIImage and NSError
typedef void (^ResponseBlock)(UIImage *image, NSError *error);

@interface ImageRequestor : NSObject

// Here you define the method that use your custom response block
- (void)getImageFromURL:(NSURL *)url withCompletionHandler:(ResponseBlock)completionBlock;

@end

几乎完成,现在打开您的 ImageRequestor.m 文件并添加以下内容:

#import "ImageRequestor.h"

@implementation ImageRequestor

- (void)getImageFromURL:(NSURL *)url withCompletionHandler:(ResponseBlock)completionBlock {
  // Do all your stuff to get the image and the error
  // And set them into your completion block
  // if there is no error that should be nil

  // completionBlock(YourFetchedImage, YourFetchedError);
  // completionBlock(nil, YourFetchedError);
  completionBlock(YourFetchedImage, nil);
}

@end

最后你可以这样调用它:

ImageRequestor *imageRequestor = [[ImageRequestor alloc] init];
[imageRequestor getImageFromURL:yourURL withCompletionHandler:^(UIImage *image, NSError *error) {
  // Your implementation in here
}];

这种东西在单例中看起来好多了 class :]

希望对您有所帮助, 祝你好运!!