Objective-C pass block as parameter

Solution 1:

The type of a block varies depending on its arguments and its return type. In the general case, block types are declared the same way function pointer types are, but replacing the * with a ^. One way to pass a block to a method is as follows:

- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;

But as you can see, that's messy. You can instead use a typedef to make block types cleaner:

typedef void (^ IteratorBlock)(id, int);

And then pass that block to a method like so:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock;

Solution 2:

The easiest explanation for this question is follow these templates:

1. Block as a method parameter

Template

- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
        // your code
}

Example

-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
        // your code
}

Other use of cases:

2. Block as a Property

Template

@property (nonatomic, copy) returnType (^blockName)(parameters);

Example

@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);

3. Block as a method argument

Template

[anObject aMethodWithBlock: ^returnType (parameters) {
    // your code
}];

Example

[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
    // your code
}];

4. Block as a local variable

Template

returnType (^blockName)(parameters) = ^returnType(parameters) {
    // your code
};

Example

void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
    // your code
};

5. Block as a typedef

Template

typedef returnType (^typeName)(parameters);

typeName blockName = ^(parameters) {
    // your code
}

Example

typedef void(^completionBlock)(NSArray *array, NSError *error);

completionBlock didComplete = ^(NSArray *array, NSError *error){
    // your code
};

Solution 3:

This might be helpful:

- (void)someFunc:(void(^)(void))someBlock;

Solution 4:

You can do like this, passing block as a block parameter:

//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
    NSLog(@"bbb");
};

//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
    NSLog(@"aaa");
    completion();
};

//invoking block "block" with block "completion" as argument
block(completion);

Solution 5:

One more way to pass block using с functions in example below. I`ve created functions to perform anything in background and on main queue.

blocks.h file

void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));

blocks.m file

#import "blocks.h"

void performInBackground(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}

void performOnMainQueue(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_main_queue(), block);
}

Than import blocks.h when necessary and invoke it:

- (void)loadInBackground {

    performInBackground(^{

        NSLog(@"Loading something in background");
        //loading code

        performOnMainQueue(^{
            //completion hadler code on main queue
        });
    });
}