#ios #objective-c #delegates #objective-c-blocks #completionhandler
#iOS #objective-c #делегаты #objective-c-блоки #обработчик завершения
Вопрос:
Объекту X необходимо загрузить изображение. У него есть URL-адрес изображения (может быть файл сети). У меня есть общий класс imageHandler, который может принимать 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 getImageFromURL: метод делегирования с делегатом как self . Он соответствует протоколу ImageRequestor.
Объект ImageHandler хранит URL-адрес для делегирования сопоставления в хеш-таблице. После того, как это будет сделано, вызывает image:RetrievedForURL:withError: для делегата. И в этом методе я действую на изображении и ошибке.
Как мне добиться того же эффекта, используя блоки завершения, где я передаю «что я хочу сделать с полученным изображением» в виде фрагмента кода.
Один из подходов, который я вижу, выглядит следующим образом. Но, похоже, для этого требуется, чтобы реализация метода 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>);
}
Ответ №1:
Да, то, что вы показали, является типичным способом сделать это. Посмотрите на собственные API Apple, чтобы увидеть, что они делают это таким же образом. Например, -[NSURLSession dataTaskWithURL:completionHandler:]
, объявление которого:
- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url
completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;
Ответ №2:
Напишите следующее в вашем 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
}];
Такого рода материалы выглядят намного лучше в одноэлементном классе :]
Надеюсь, это поможет, Удачи!!