Reputation: 3527
I've been through a few Stack Overflow questions and I can't seem to figure how to adapt my code to include a failure block. How can I add a failure block to this code?
+ (void)loginUser:(NSString *)username withPassword:(NSString *)password :(void (^)(BOOL finished))completionBlock {
NSString *endpoint = @"Users/Login";
[self postEndpoint:endpoint params:[NSMutableDictionary dictionaryWithObjectsAndKeys:username, @"Username", password, @"Password", nil] completionBlock:^(DollarResponse *response) {
NSLog(@"%@",response);
if ([response.result isEqual:[NSNull null]]) {
[self displayError:response.message];
} else {
Login *login = [[Login alloc] initWithDictionary:response.result];
[self saveLogin:login];
completionBlock(YES);
}
}];
/* loginUser:withPassword:: */
Upvotes: 1
Views: 701
Reputation: 19114
I prefer to use a generic and simplistic completion block for asynchronous methods when possible and when suitable as in your case. There is no special "failure" block - since the failure case will be handled by the call-site directly in the completion block. See example below:
typedef void (^completion_t)(id result);
-(void) loginUser:(NSString *)username
withPassword:(NSString *)password
completion:(completion_t)completionHandler;
(see below for a better naming of the method)
In the documentation you state:
The result parameter returns @"OK" in case of success, otherwise a NSError object containing details about the error.
(Of course, you may return something different, and more suitable as the result in case of success)
Well, then you may use it as follows:
[foo loginUser:user withPassword:pass completion:^(id result){
if (![result isKindOfClass:[NSError class]]) {
...
}
else {
NSLog(@"Error: %@", error);
}
}];
There are countless other valid and reasonable signatures for a completion handler:
typedef void (^completion_t)(NSData* data, NSError* error);
This one, apparently, returns a NSData in case of success, and a NSError in case of a failure. The documentation shall specify the details.
You may define different handlers (blocks) as properties when you have an Operation object which performs an asynchronous task (e.g., a subclass of NSOperation
) Since your example deals with an asynchronous method, there's no reason to explain that here, unless you post a new question. ;)
Edit:
According the naming conventions, I would suggest the following:
-(void) loginWithUsername:(NSString *)username
password:(NSString *)password
completion:(completion_t)completionHandler;
Upvotes: 2
Reputation: 14237
First of all you need to pass your block. It is useful to define a type for that:
typedef void (^MyErrorBlock)(NSString* error);
Note that your are going to pass an error in that block as a NSString
because your response.message
it seems like a string. Although usually error blocks pass an NSError
.
To pass it as a parameter you can do:
-(void)loginUser:(NSString *)username
withPassword:(NSString *)password
(void (^)(BOOL finished)): completionBlock
(MyErrorBlock): errorBlock
Then you can call it as you call your completionBlock, but you then pass response.message
like this:
errorBlock(response.message)
You can also save a pointer to your errorBlock and then call it when you need it.
Upvotes: 2