美文网首页iOS归纳
iOS - Block的写法及使用

iOS - Block的写法及使用

作者: 码代码的小马 | 来源:发表于2021-05-01 15:22 被阅读0次

    Block技术合集
    iOS - Block变量截获

    1. Block定义

        //声明定义
        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 = 3
    

    这段代码等号左侧声明一个名为sumOfNumbers的代码块,名称前用^符号表示后面的字符串是block的名称。最左侧的int表示这个block的返回值,括号中间表示这个block的参数列表,这里接收两个int类型的参数。 而在等号右侧表示这个block的定义,其中返回值是可以省略的,编译器会根据上下文自动补充返回值类型。使用^符号衔接着一个参数列表,使用括号包起来,告诉编译器这是一个block,然后使用大括号将block的代码封装起来。


    Block

    2. Block写法

    • return_type 表示返回的对象/关键字等(通常是void)
    • blockName 表示block的名称
    • var_type 表示参数的类型
    • varName 表示参数名称
    1. 做为局部变量
    
    
    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;
    };
    

    2. 做为属性
    @property (copy) return_type (^blockName) (var_type);
    @property (nonatomic, copy) void(^ didLoginSuccess)(NSString *username);
    @property (nonatomic, copy) void(^ didLoginFailed)(void);
    
    3. 定义方法时,做为Block型的形参数
    - (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();
    }
    
    4. Block作为实参

    Block作为参数使用,常见于各框架之中,比如在封装一个类时,当做什么事情由外界去决定,什么时候调用由自己的类决定时,这时候就需要将block作为参数使用。

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

    以自定义一个简单的工具类CalculatorManager为例:

    //
    //  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作为参数时格式与其它类型定义时一致,都是(类型)变量名,看起来有些晕人
    - (void)calculate:(int(^)(int))calculateBlock;
    
    @end
    
    //
    //  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];
    }
    
    //方法中定义了一个block数据类型参数(返回值为int类型的,且带有一个int类型的形参)
    - (void)calculate:(int (^)(int))calculateBlock {
        //calculateBlock接受外界传入的代码块,也就意味着怎么去操作是由外界调用者决定的
        _result = calculateBlock(defaultHeight);
    }
    
    @end
    

    外界控制器调用

        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);
    

    可以看到,工具类CalculcatorManager的计算方法calculate:^int(int)calculateBlock其具体实现,交由了外界的控制器调用者去决定了。虽然有些许绕,但只要搞清楚block的作为参数使用时的格式,理解起来也很快的,如果先前对这类型的用法在理解上抱有疑惑的话,希望这个小例子能帮到您:)

    5. 匿名Block

    Block实现时,如上文的局部变量和实参,等号右边就是一个匿名Block,它没有blockName:

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

    利用typedef简化Block的声明

    typedef return_type (^BlockTypeName)(var_type);
    typedef void (^didQuitAcountBlock)(void);
    

    使用

    BlockTypeName aBlock = ^return_type (var_type) {
        //...
    }
    
    didQuitAcountBlock quitBlock = ^void(void) {
      NSLog(@"did quit acount");
    };
    quitBlock();
    
    7. 内联 Block

    这种形式并不常用,匿名Block声明后立即被调用,内联 Block可用于代码分块,提高代码可读性,功能类似大括号的代码块,其它功能非常有限

    ^return_type (var_type varName)
    {
        //...
    }(var);
    
    ^void() {
            NSLog(@"内联Block声明后即被调用");
     }();
    
    8. 递归调用Block

    Block内部调用自身,递归调用是很多算法基础,特别是在无法提前预知循环终止条件的情况下。
    注意 由于Block内部引用了自身,这里必须使用__block避免保留环问题。

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

    实例

        __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();
    
    8. Block做为返回值
    - (return_type(^)(var_type))methodName
    {
        // ...
    }
    

    3. 一个Block传参的例子

    .h

    @interface SecondViewController : UIViewController
    
    @property (nonatomic, copy) void(^ didLoginSuccess)(NSString *username);
    
    @property (nonatomic, copy) void(^ didLoginFailed)(void);
    
    @end
    

    .m

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        if (self.didLoginSuccess) {
            self.didLoginSuccess(@"码代码的小马");
        }
        
        if (self.didLoginFailed) {
            self.didLoginFailed();
        }
    }
    

    调用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");
        };
    

    相关文章

      网友评论

        本文标题:iOS - Block的写法及使用

        本文链接:https://www.haomeiwen.com/subject/xcyarltx.html