• Block


    一、简述

      1.1 block是1个数据类型.

            BOOL、Boolean、class、nil、SEL、id、block。

      1.2  block是一个数据类型.

            int double float char .......

            既然是1个数据类型,那么就可以声明这个数据类型的变量,所以我们完全可以声明1个block类型的变量.

            不同类型的变量中可以存储不同类型的数据.

            那么block类型的变量中可以存储什么样的数据呢?

            1). block是1个数据类型 所以我们可以声明1个block类型的变量.

            2). block类型的变量中专门存储1段代码,这段断码可以有参数 可以有返回值.

      1.3 block的声明

        1). 虽然block变量中是用来存储1段代码的,但是1个block变量中并不是任意的1段代码都可以存进去的

                而是有限定的.

                  也就是说,在声明block变量的时候,必须要镇定这个block变量存储的代码是否有参数,是否有返回值.

                  一旦指定以后,这个block变量中就只能存储这样的代码了.

                声明了1个block变量,返回值是void 参数是1个int类型的.

                这个时候,这个block变量中就只能存储无返回值且有1个int参数的代码段.

        2). 声明block变量的语法格式:

                  返回值类型 (^block变量的名称)(参数列表);

                  void (^myBlock1)(); 表示声明了1个block类型的变量叫做myBlcok1 这个变量中只能存储没有返回值没有参数的代码段.

                  int (^myBlock2)();        

                  int (^myBlock3)(int num1,int num2);

        3). 备注

                  声明block变量的时候要指定这个block变量可以存储的代码段的返回值和参数描述,

                  一旦指定,这个block变量中就只能存储这样的代码段了,其他格式的代码段无法存储.

      1.4 初始化block变量  

        1). 原理: 写1歌复合block要求的代码段,存储到block中就可以了.

        2). 代码段的书写格式:

                   ^返回值类型(参数类表) {

                       NSLog(@"Who are you");

                       NSLog(@"Where are yon going");

                   }

        3). 写一个无参数无返回值的代码段. 

          ^void() {

                       NSLog(@"Who are you");

                       NSLog(@"Where are yon going");

                  };

          这个时候,我们就可以将这段代码段使用赋值符号存储到 无返回值五参数要求的block变量中.

                  void (^myBlock1)();

                   myBlock1 = ^void() {

                       NSLog(@"Who are you");

                       NSLog(@"Where are yon going");

                   };

        

        4). 有返回值的代码段.

                  ^int() {

                      int num1 = 10 + 20;

                      return num1;

                  };

                  我们就可以将这段代码赋值给符合要求的block变量.

                  int(^myBlock2)() = ^int() {

                      int num1 = 10 + 20;

                      return num1;

                  };

        

        5). 既有参数既有返回值的代码段.        

                  ^int(int num1,int num2) {

                      int num3 = num1 + num2;

                      return num3;

                  };

                  所以 我们可以将这个代码赋值给符合要求的block变量.

                  int (^myBlock3)(int num1,int num2) = ^int(int num1,int num2) { 

                      int num3 = num1 + num2;

                      return num3;

                  }

        6). 注意.

                  赋值给block变量的代码段必须要符合block变量的要求,否则就会报错.

      

      5. 如何执行存储在block变量中的代码段.

              语法格式: block变量名(); 

              有参数就传,有返回值就接.

      6. 关于block的简写.    

        1). 如果我们写的代码段没有返回值.那么代码段的void可以省略.

                  void(^myBlock1)() = ^() {

                  };

                  注意,代码段的返回值是void可以省略,声明block变量的返回值无论是什么不可省略. 

      2). 如果我们写的代码段没有参数,那么代码段的小括弧可以省略.      

                  int(^myBlock2)() = ^int{

                       int num1 = 10 + 20;

                  return num1;

                  }

                  再次强调: 我们说的是代码段.

                  所以,当1个代码段没有参数,也没有返回值的时候,就只写

                    void(^myBlock3)() = ^{

               NSLog(@"Who are you");

                         NSLog(@"Where are yon going");

                    }

        3). 声明block变量的时候,如果有指定参数,可以只写参数类型而不写参数的名称;    

          int (^myBlock3)(int,int) = ^int(int num1,int num2) {

                    int num3 = num1 + num2;

                    return num3;

                }      

          注意: 这个地方我们说的是声明block变量的时候 在写代码段的时候 类型和名称都要写.

        4). 无论代码段是否有返回值,在写代码的时候,可以不写返回值类型

                   如果在写代码段的时候,省略了返回值,这个时候系统会自动的确定返回值类型.

          

          如果代码段中没有返回任何数据, 那么它会认为这个代码段是没有返回值的.

                   如果代码中有返回数据 返回的数据是什么类型 它就会认为这个代码段是什么类型的.

               int(^myBlock3)(int num1,int num2) = ^(int num1,int num2) {

                     int num3 = num1 + num2;

                     return num3;

                };

          一般: 仍然按照我们最标准的写法来写block变量和block代码段.因为这样可以提高代码的阅读性.

      1.7. 简化block变量的复杂定义.

        1). 问题: 定义block变量的时候,要写好大1串啊! 类型好长.

        2). typedef的使用场景: 将1个长类型定义为1个短类型.

        3). 使用typedef将长的block类型 定义为1个段类型. 

                  typedef 返回值类型(^新类型)(参数列表);

                  typedef void(^NewType)(); 代表重新定义了1个类型叫做NewType 是一个block类型 无参数无返回值的block类型

      1.8. 关于block块访问外部变量的问题. 

        1). 在block代码块的内部可以去定义在外部的变量的值,定义在外部的局部变量和全局变量.

        2). 在block代码快的内部可以修改全局变量的值,但是不能修改定义在外部的局部变量的值.

        3). 如果你希望我们定义的局部变量可以允许在block代码的内部去修改,那么就为这个局部变量加1个__block的修饰符.

        

    二 、使用场景 - 2018.01.06

    •  1. 保存到对象中,恰当时机的时候调用
    •  2. 当做方法的参数使用,外界不调用,都是方法内部调用,Block实现交给外界决定。  --- 实现再外部
    •  3. 把block当作方法的返回值。目的就是为了代替方法。blcok交给内部实现,外界不需要知道Block怎么实现,只管调用。 --- 实现再内部

    2.1 保存在对象,合适时调用

    -(void)block {

        void(^block)() = ^() {

            //保存什么样的代码  

            NSLog(@"执行block");

        };

        //block作用: 帮你保存一份代码,等到恰当时机的时候采取调用   

        //调用block

        block();

    }

    2.2 作为参数

    -(void)block2 {

        Person *p = [[Person alloc] init];

        void(^blcok)() = ^() {  

            NSLog(@"--------");

        };

        p.operation = ^{  

            NSLog(@"******************************");

        };

        p.operation = blcok;

        _p = p;

    }

    -(void)block3 {

        Person *p = [[Person alloc] init];

        [p eat:^{       

            NSLog(@"吃东西");

        }];

    }

    2.3 作为返回值

    Person *p = [[Person alloc] init];

    p.run(2);

    *附(Class Person):

    @interface Person : NSObject

    //block:ARC使用strong,非ARC使用copy

    @property (nonatomic,strong) void(^operation)();

    -(void)eat:(void(^)())block;

    //-(void)run:(int)metre;

    -(void(^)(int ))run;

    @end

    ------------

    @implementation Person

    -(void)eat:(void(^)())block {

        block();   

    }

    -(void(^)(int))run {

        return ^(int metre) {       

            NSLog(@"跑了%d米",metre);

        };

    }

    @end

    喜欢请赞赏一下啦^_^

    微信赞赏

    支付宝赞赏

  • 相关阅读:
    Java编程思想学习(三)----第三章:操作符
    mybatis入门
    responsebody和requestbody的使用
    一个Interface 继承多个Interface 的总结
    requirejs中Shims使用说明
    java 中解析json步骤
    @transient加在属性前的作用
    实现serializable接口的作用
    springmvc源码解析-初始化
    @RequestMapping注解详解
  • 原文地址:https://www.cnblogs.com/share-iOS/p/6876082.html
Copyright © 2020-2023  润新知