Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create my own completion handler as part of method parameters

I want to create a completion handler for a certain class, instead of firing off the class's main code and waiting for a delegate callback. I've read through the Apple documentation and they don't seem to give a very good example of how to directly implement something like this.

like image 997
user2070259 Avatar asked Feb 13 '13 23:02

user2070259


People also ask

What is a completion block?

The block to execute after the operation's main task is completed.

What is completion block in Swift?

Swift Closures with Completion handler Closures are self-contained blocks of functionality that can be passed around and used in your code. Said differently, a closure is a block of code that you can assign to a variable. You can then pass it around in your code, for instance to another function. … 7 min read.


3 Answers

You need to treat the completion block just like a variable. The method will accept a block as part of it's parameters, then store it for later.

- (void)myMethodWithCompletionHandler:(void (^)(id, NSError*))handler;

You can typedef that block type for easier reading:

typedef void (^CompletionBlock)(id, NSError*);

And then store your block as an instance variable:

In your @interface: CompletionBlock _block;

In the myMethod.. _block = [handler copy]

Then when you want the completion block to execute you just call it like a regular block:

_block(myData, error);

like image 135
Chris C Avatar answered Oct 16 '22 07:10

Chris C


If it was for an asynchronous method you could do it like this

- (void)asynchronousTaskWithCompletion:(void (^)(void))completion;
{
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    // Some long running task you want on another thread

    dispatch_async(dispatch_get_main_queue(), ^{
      if (completion) {
        completion();
      }
    });
  });
}

this would be invoked with

[self asynchronousTaskWithCompletion:^{
  NSLog(@"It finished");
}];

Something to note is the guard to make sure that completion is pointing to something otherwise we will crash if we try to execute it.

Another way I often use blocks for completion handlers is when a viewController has finished and want's to be popped from a navigation stack.

@interface MyViewController : UIViewController

@property (nonatomic, copy) void (^onCompletion)(void);

@end

@implementation MyViewController

- (IBAction)doneTapped;
{
  if (self.onCompletion) {
    self.onCompletion();
  }
}

@end

You would set the completion block when pushing this view onto the stack

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
{
  MyViewController *myViewController = segue.destinationViewController;
  myViewController.onCompletion = ^{
    [self.navigationController popViewControllerAnimated:YES];
  };
}
like image 33
Paul.s Avatar answered Oct 16 '22 07:10

Paul.s


Heres an example for a method that takes a String and a completion handler as variables. The completion handler can also receive a String.

Swift 2.2 Syntax

Defintion:

func doSomething(input: String, completion: (result: String) -> Void {
    print(input)
    completion(result: "we are done!")
}

Calling the function:

doSomething("cool put string!") { (result) in
        print(result)
}
like image 4
realtimez Avatar answered Oct 16 '22 06:10

realtimez