https://www.appcoda.com/objective-c-blocks-tutorial/

A block is a self-contained, autonomous code fragment.

They can be used instead of delegate methods, written just in one place and not spread to many files.

Blocks are objects, so they can be stored to NSArray or NSDictionary data structures, as well as to be returned from methods, even to be assigned to variables.

ReturnType (^blockName)(Parameters);
NSString *(^composeName)(NSString *, NSString *);

If you return a value, you need a return statement.

int (^howMany)(int, int) = ^(int a, int b){
    return a + b;
};

But if you return void no return statement if needed.

void (^justAMessage)(NSString *) = ^(NSString *message){
   NSLog(@"%@", message);
};

You can declare a block, and then define it later.

    // Declare a block variable.
    void (^xyz)(void);
    
    // Some other code...
    
    // Define the block.
    xyz = ^(void){
        NSLog(@"What's up, Doc?");
    };

You can also define it as a property.

@interface ViewController ()
@property (nonatomic, strong) NSString *(^blockAsAMemberVar)(void);
@end

And then formally define it later.

_blockAsAMemberVar = ^(void){
        return @"This block is declared as a member variable!";
};

You call a block just like a C function

int (^howMany)(int, int) = ^(int a, int b){
        return a + b;
};

    
NSLog(@"%d", howmany(5, 10));

Here’s another

    NSDate *(^today)(void);
    
    today = ^(void){
        return [NSDate date];
    };
    
    NSLog(@"%@", today());

And if you ever need to change a variable within a block, use the double underscore

-(void)testBlockStorageType{
    __block int someValue = 10;
    
    int (^myOperation)(void) = ^(void){
        someValue += 5;
        
        return someValue + 10;
    };
    
    NSLog(@"%d", myOperation());
}

Blocks as Completion Handlers

A completion handler is the way for implementing callbacks using blocks.
A completion handler is nothing more than a block declaration passed as a parameter.

andCompletionHandler:(void(^)())completionHandler;
andCompletionHandler:(void (^)(int result))completionHandler;

This flips the functionality of the paremeters from being one of inputs, to being one of outputs returned by the block.

andCompletionHandler:(void(^)(<any block params>))completionHandler{
    ...
    ...
 
    // When the callback should happen:
    completionHandler(<any required parameters>);
}

By passing it as a parameter, we can call it from within out method passing in the paremeters we want to return to the original calling method. We flip it around. So instead of using the parameters passed in, we set them and return them on when we call the block.

There is nothing magically asynchronous about blocks by themselves. They are called synchronously just like any other code.

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self addNumber:5 withNumber:7 andCompletionHandler:^(int result) {
        NSLog(@"The result is %d", result);
    }];
}

-(void)addNumber:(int)number1 withNumber:(int)number2 andCompletionHandler:(void (^)(int result))completionHandler{
    int result = number1 + number2;
    completionHandler(result);
}

But what’s cool about blocks. You can do asynchronous things by throwing them onto different threads.

NSLog(@"Preparing to run code in secondary thread...");
    dispatch_queue_t myQueue = dispatch_queue_create("My Queue", NULL);
    dispatch_async(myQueue, ^{
        NSLog(@"Running code in secondary thread...");
        
        int value = 0;
        for (int i=0; i<100; i++) {
            for (int j=0; j<100; j++) {
                for (int n=0; n<100; n++) {
                    value += j;
                }
            }
        }
        
        NSLog(@"From secondary thread: value = %d", value);
    });
    
    NSLog(@"This is main thread again...");
Advertisements