user1898829
user1898829

Reputation: 3527

How do I add a failure block objective-c

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

Answers (2)

CouchDeveloper
CouchDeveloper

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

Tiago Almeida
Tiago Almeida

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

Related Questions