I'm diving into iOS programming and I'm learning how to use blocks. I have a sucky, over-engineered library that I'm using in my project and it uses a single callback method to handle all data requests...
@protocol SuckyClassDelegate <NSObject>
-(void)returnedSuckyData:(NSMutableDictionary*)data;
@end
@interface SuckyClass: NSObject
@property (nonatomic, weak) id<SuckyClassDelegate> delegate;
-(void)getSuckyData;
@end
@interface MyViewController: UIViewController <SuckyClassDelegate>
-(void)requestDataFromSuckyClass;
@end
I'd like to create a wrapper class for the SuckyClass that allows me to use blocks when I need to access data from the SuckyClass, but I don't know how to do this. I'd like to have something like this...
@interface SuckyClassWrapper
- (void)requestDataWithSuccessBlock:(void(^)((NSMutableDictionary*)data))successBlock;
@end
@implementation MyViewController
-(void)requestDataFromSuckyClass {
SuckyClassWrapper *wrapper = [[SuckyClassWrapper alloc] init];
[wrapper requestDataWithSuccessBlock:^(NSMutableDictionary *data) {
NSLog(@"%@", data);
}
}
@end
...but I can't figure out how to convert the callback process into blocks. Can anyhow give me some direction here?
Thanks in advance for your wisdom!
By the way, I just whipped up the code without testing it, so I apologize if there are any typos.
The trick is to copy the completion block to a class iVar that you can then call later.
@property (nonatomic, copy) void (^errorHandler)(NSError *);
@property (nonatomic, copy) void (^successHandler)(NSString *);
Here is a method that saves two blocks for use later and then calls another class method:
- (void)methodWithErrorHandler:(void(^)(NSError *error))errorBlock successHandler: (void(^)(NSString *data))successBlock
{
// Copy the blocks to use later
self.successHandler = successBlock;
self.errorHandler = errorBlock;
// Run code
[self doOtherThings];
}
Later - when what we want to do has completed, we have another method that we call to run the blocks. In this silly example code we check to see if a class property self.error
is nil
. If it is not nil
, we send that error to our saved error block. If it is nil
, we pass self.data
to the success block.
- (void)finishThingsUp
{
// Check to see if we should call the error block or the success block
if (self.error) {
self.errorHandler(self.error);
} else {
self.successHandler(self.data);
}
// Clean up the blocks
self.errorHandler = nil;
self.successHandler = nil;
}
We could use like this:
typedef void (^SuccessDataBlock)(NSMutableDictionary *);
@interface SuckyClassWrapper : NSObject <SuckyClassDelegate>
@property (nonatomic, retain) NSData *inputData;
@property (nonatomic, copy) SuccessDataBlock completionHandler;
+ (id)requestData:(NSData *)data successBlock:(SuccessDataBlock)handler;
@end
@implementation SuckyClassWrapper
@synthesize inputData;
@synthesize completionHandler;
- (id)initWithData:(NSData *)data completionHandler:(SuccessDataBlock)handler
{
self = [super init];
if (self != nil)
{
inputData = [data retain];
self.completionHandler = handler;
}
return self;
}
+ (id)requestData:(NSData *)data successBlock:(SuccessDataBlock)handler
{
return [[[self alloc] initWithData:data completionHandler:handler] autorelease];
}
//implement SuckyClass delegate
- (void)returnedSuckyData:(NSMutableDictionary *)data
{
self.completionHandler(data);
}
@end
Usage:
SuckyClassWrapper *wrapper = [SuckyClassWrapper requestData:data successBlock:^(NSMutableDictionary *successData) {
//your code here
}];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With