1

Using inheritance.

I have a child class that calls a method in the parent class that runs calls the server API.

-(IBAction)buttonPressed
{
    [self methodInParentClassThatCallsTheAPI:param];
    // This is where I would like the call back
     if (success from the server API) // do something with the UI
     else if (failure from the server API) // do so something else with the UI
}

Parent Class:

- (void)methodInParentClassThatCallsTheAPI:(NSString *)param
{
      //The method below calls the server API and waits for a response.  
      [someServerOperation setCompletionBlockWithSuccess:^(param, param){
        // Return a success flag to the Child class that called this method
      } failure:^(param, NSError *error){
        // Return a failure flag to the Child class that called this method
      }
}

How can I accomplish this with a block? Is there a better way to do this other than the block? Code example please

user1107173
  • 10,334
  • 16
  • 72
  • 117

1 Answers1

4

Create a completion block on methodInParentClass like this:

- (void)methodInParentClassThatCallsTheAPI:(NSString *)param completionBlock:(void (^)(BOOL success))completionBlock;

Then fire it inside the block success/failure with the appropriate value like this:

completionBlock(YES);

EDIT: By the way, please note that the return may not be on the main thread so if you plan to do a UI update you can fire the return block with a dispatch_async(dispatch_get_main_queue, ^{});

EDIT2: Since you seem to suggest this is the result of a button tap if your child is a VC waiting on the return just remember that this block will return async (obviously since that's what it is designed for) so if you need to hold the user for whatever reason you'll need to have the main thread display a loading indicator of some sort and hold user input events. Just remember that if you don't the UI will continue responding when before the completion block fires so at the very least you will want to disable the button so the user can't multi-press it and then you can reenable it when the completion block fires from the child VC.

EDIT3: Ok here is the calling code.

-(IBAction)buttonPressed
{
    [self methodInParentClassThatCallsTheAPI:param withCompletionBlock:^(BOOL success){
        if (success) {
          // do something with the UI
        } else {
            // Do something else
        }
    }];
}
smyrgl
  • 864
  • 6
  • 12
  • How would I call this method? Thanks. – user1107173 May 07 '14 at 01:54
  • 1
    Like you would any block method. You are doing so with that `someServerOperation` method above, this is exactly the same thing. – smyrgl May 07 '14 at 01:56
  • What will I pass in the block? – user1107173 May 07 '14 at 01:56
  • 1
    See those if/else statements in your child VC that update the UI? They would go in that completion block and get fired when the method returns but see my edit above so you understand the behavior and make sure that you do any UI updates on the main thread. – smyrgl May 07 '14 at 01:57
  • 1
    For clarity: you are passing a block from the VC to the parent controller and saying "run the code in this block when you are done". It is also promising that you will have a local variable set to the outcome of the operation which is what that BOOL success in the completion block is for. Just try it, it will do what you want. – smyrgl May 07 '14 at 01:59
  • 1
    One other thing: if you pass nil to the completion block it will crash your code if you try calling completionBlock(YES) or completionBlock(NO). For safety it is good practice with completion blocks like this to say: if(completionBlock) ... before you fire it as some callers may not care about the completion block. – smyrgl May 07 '14 at 02:00
  • updating UI on the main thread I get. But, can you please do an edit showing how to call this method from the Child class? i.e. [self methodInParentClassThatCallsTheAPI:param completionBlock://What do I pass here?]; – – user1107173 May 07 '14 at 02:02