Block technology collection

Ios-block variable interception

1. The Block definition

Int (^ sumOfNumbers)(int a, int b) = (int a, int b) {return a + b; }; int sum = sumOfNumbers(1, 2); NSLog(@"sum = %d", sum); 2021-05-01 11:04:05.920543+0800 BlockDemo[18351:6429226] sum = 3Copy the code

This code declares a block named sumOfNumbers to the left of the equals sign, preceded by the ^ sign indicating that the string following the name is the block name. The leftmost int represents the return value of the block, and the parentheses between them represent the argument list of the block, which receives two ints. The right side of the equal sign represents the definition of the block, where the return value can be omitted and the compiler automatically supplements the return value type based on the context. A list of arguments is concatenated with the ^ symbol, wrapped in parentheses, telling the compiler that this is a block, and then wrapping the block’s code with curly braces.

2. Block method

  • return_typeRepresents returned objects/keywords, etc. (usuallyvoid)
  • blockNamesaidblockThe name of the
  • var_typeRepresents the type of the parameter
  • varNameParameter name
1. As a local variable
Copy the code
return_type (^blockName)(var_type) = ^return_type (var_type varName) {
    // ...
};
blockName(var);

int(^ sumOfNumbers)(int a, int b) = ^(int a, int b) {
  return a + b;
};
Copy the code

2. As an attribute
@property (copy) return_type (^blockName) (var_type);
@property (nonatomic, copy) void(^ didLoginSuccess)(NSString *username);
@property (nonatomic, copy) void(^ didLoginFailed)(void);
Copy the code
3. Define the method as a Block parameter
- (void)yourMethod:(return_type (^)(var_type))blockName;
- (void)sumOfA:(int)a B:(int)b sumBlock:(void(^)(int sum))sumBlock {
    int sum = a + b;
    sumBlock(sum);
}

- (void)login:(void(^)(void))completion {
    completion();
}
Copy the code
4. Block is the argument

The use of blocks as arguments is common in various frameworks, such as when wrapping a class, when the outside world decides what to do and when to call its own class.

[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
    //...
}];
Copy the code

Take customizing a simple tool class CalculatorManager as an example:

// // CalculatorManger.h // BlockDemo // // Created by Ternence on 2021/5/1. // #import <Foundation/Foundation.h> @interface CalculatorManger: NSObject @property (nonatomic, assign) int result; + (instancetype)sharedManager; //block is defined in the same format as other types, which are (type) variable names and look a bit confusing - (void)calculate:(int(^)(int))calculateBlock; @endCopy the code
// // CalculatorManger.m // BlockDemo // // Created by Ternence on 2021/5/1. // #import "CalculatorManger.h" static int defaultHeight = 100; static CalculatorManger * instance = nil; @implementation CalculatorManger + (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (instance == nil) { instance = [super allocWithZone:zone]; }}); return instance;; } + (instancetype)sharedManager { return [[self alloc] init]; } // the method defines a block datatype argument (return int, Calculate :(void)calculate:(int (^)(int))calculateBlock {//calculateBlock accepts code blocks passed in, _result = calculateBlock(defaultHeight); } @endCopy the code

External controller call

    CalculatorManger *manager = [CalculatorManger sharedManager];
    [manager calculate:^int(int i) {
        NSLog(@"=======i : %d", i);
        for (int j = 0; j < 100; j ++) {
            i++;
        }
        return i;
    }];
    
    NSLog(@"=====result: %d", manager.result);
Copy the code

It can be seen that the calculation method of CalculcatorManager of tool class calculateBlock calculate:^int(int)calculateBlock is left to external controller callers to decide. It’s a bit convoluted, but it’s easy to understand once you know the format of a block as an argument. If you were confused about the use of this type, hopefully this little example will help you 🙂

When a Block is implemented, such as the local variable and argument above, the right side of the equal sign is an anonymous Block, which has no blockName:

^return_type (var_type varName)
{
    //...
};
Copy the code
6. typedef Block

Use typedef to simplify Block declarations

typedef return_type (^BlockTypeName)(var_type);
typedef void (^didQuitAcountBlock)(void);
Copy the code

use

BlockTypeName aBlock = ^return_type (var_type) {
    //...
}

didQuitAcountBlock quitBlock = ^void(void) {
  NSLog(@"did quit acount");
};
quitBlock();
Copy the code
7. An inline Block

This form is not commonly used. Anonymous blocks are called immediately after they are declared. Inline blocks can be used to Block code, improving readability

^return_type (var_type varName) { //... }(var); ^void() {NSLog(@" called after inline Block declaration "); } ();Copy the code
8. Call Block recursively

A Block calls itself internally, and recursive calls are the basis for many algorithms, especially if loop termination conditions cannot be predicted in advance. Note that since blocks refer to themselves internally, __block must be used here to avoid the retention ring problem.

__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
    if (returnCondition)
    {
        blockName = nil;
        return;
    }
    // ...
    blockName(varName);
} copy];
blockName(varValue);
Copy the code

The instance

    __block int i = 5;
    __block void (^ dismisssController)(void) = [^void(void) {
        if (i == 0) {
            dismisssController = nil;
            return;
        }
        
        NSLog(@"recursionBlock i = %d", i);
        i --;
        dismisssController();
    } copy];
    dismisssController();
Copy the code

######8. Block is returned

- (return_type(^)(var_type))methodName
{
    // ...
}
Copy the code

3. An example of Block parameter transmission

.h

@interface SecondViewController : UIViewController

@property (nonatomic, copy) void(^ didLoginSuccess)(NSString *username);

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

@end
Copy the code

.m

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ if (self.didLoginSuccess) { Self. DidLoginSuccess (@" code code for the ponies "); } if (self.didLoginFailed) { self.didLoginFailed(); }}Copy the code

Call block,

    SecondViewController *vc = [[SecondViewController alloc] init];
    [self.navigationController pushViewController:vc animated:true];
    
    vc.didLoginSuccess = ^(NSString * _Nonnull username) {
        NSLog(@"congratulations %@! welcome to objc world", username);
    };
    
    vc.didLoginFailed = ^{
        NSLog(@"login failed");
    };
Copy the code