zoukankan      html  css  js  c++  java
  • C 【block类型全方位详解】

    ———————————————————————————————————————————
    block变量的概念

    #import <Foundation/Foundation.h>

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    //        block 是一个数据类型
    //        block 和函数非常相似
    //        函数不能在另一个函数的内部嵌套,但是block因为不是函数所以说可以在main里面写

    //        *****************************************************************************************
            
    //        无参的block变量定义
    //        书写格式:    返回值类型 (^block变量名) (参数) =^{  代码块;  };
    //        调用格式:    block变量名();
    //        意义:在需要的地方调用
           
            void (^myBlock1)() = ^{
                NSLog(@"1234");
            };
            
            myBlock1();

            void (^blocklalala)(void)=^(void){
                NSLog(@"lalala");
            };
            
            blocklalala();
            
    //        *****************************************************************************************
            
    //        有参的block变量定义
    //        书写格式:    返回值类型 (^block变量名) (参数类型列表) =^(形参列表){    代码块;   };
    //        调用格式:    block变量名(实参列表);
            void (^eat)(int ,int )=^(int x,int y){ //a,b表示这个block变量有两个参数,且都是int类型的。而后面的x,y就是类似于函数的形参了
                NSLog(@"x+y=%d",x+y);
            };
            
            eat(10,10);
            
            void (^wangzhongyao)(int ,int )=^(int a,int b){
                NSLog(@"a+b=%d",a+b);
            };
            
            wangzhongyao(10,14);
            wangzhongyao(1,2);
            
    //        *****************************************************************************************
            
    //        带有参数和返回值的block变量定义
            int (^blockSum)(int ,int ,int )=^(int a,int b,int c){
                return a+b+c;
            };
            NSLog(@"blockSum=%d",blockSum(1,2,3));

    //        *****************************************************************************************
            
    //        注意:block变量的返回值可以是其他的block类型
            
        }
        return 0;
    }


    ———————————————————————————————————————————
    block的typedef用法

    事实上,typedef是为block起了一个别名。这和函数指针比较的相似。

    注:指针和函数
     
       1)指针函数   (返回值是指针的函数)
       2)函数指针   (指向函数的指针)


    #import <Foundation/Foundation.h>

    int sum(int x,int y)
    {
        return x+y;
    }

    void test1()
    {//函数指针的回顾
        int s=sum(5, 10);
        NSLog(@"s=%d",s);
        
        //        定义指向函数的指针
        int (*p)(int x,int y);
        p=sum;
        s=p(3,5);
        NSLog(@"s=%d",s);
        
        //        给函数指针起个别名
        typedef int (*newType)(int x,int y);//newType 就是一个新类型,而不是函数名
        newType p2=sum;//用新的函数指针类型定义一个新的函数指针变量p2,然后用p2指向sum
        
        s=p2(1,2);
        NSLog(@"s=%d",s);
        
    }

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    //********************************给无参无返回值的block变量重命名**************************************
            
    //        先建立一个无参无返回值的block
            void (^myBlock)()=^{
                NSLog(@"这是原来的block!");
            };
            myBlock();
            
    //        给无参无返回值的block类型起一个别名
            typedef void (^newMyBlock)();
    //        注意:和指针函数差不多,这里的newMyBlock是一个 新的类型,而不再是block类型的变量名了
            newMyBlock f1;//定义一个 无参无返回值的变量f1
            f1=^{
                NSLog(@"这是通过typedef创建的新类型所定义的block");
            };
            f1();
            
    //********************************给有参有返回值的block变量重命名**************************************
            
    //        先建立一个有参有返回值的block
            int (^sumBlock)(int ,int ,int )=^(int x,int y,int z){
                return x+y+z;
            };
            int sum1=sumBlock(1,2,4);
            NSLog(@"sum1=%d",sum1);
            
    //        给有参有返回值的block起一个别名
            typedef int (^newTypeForSum)(int ,int ,int );//这里实际上是定义了一个新的类型,而这个新的类型的类型名是newTypeForSum,这个新的类型是一个 返回值是int类型并且有三个int类型的参数的block类型。
            
            newTypeForSum f2;//用新的block类型声明了一个变量f2
            f2=^(int x,int y,int z){
                return x*y*z;//显然这里可以是对三个参数的任何操作。
            };
            
            int s3=f2(3,5,2);
            NSLog(@"s3=%d",s3);
            
            
    //        再写一个block类型,显然我们根本不用先写一个block变量然后再起别名(下面三行代码可以不要),我们可以直接用typedef去写一个新的block类型
    //        int (^sumBlock1)(int ,int )=^(int x,int y){
    //            return x+y;
    //        };
            
            typedef int (^newType1)(int ,int);//直接写了一个返回值是int类型且有两个int类型的参数的新的block类型
            newType1 f3;
            f3=^(int a,int b){
                return a*b;//在新block类型变量内部定义方法
            };
            int ss=f3(12,12);
            NSLog(@"ss=%d",ss);
        }
        return 0;
    }


    ———————————————————————————————————————————
    block访问外部变量

    /*
     局部变量: 在函数的内部或者代码块的内部定义的变量,都是局部变量
     (局部变量存在于内存的栈区)
     
     全局变量: 在函数的外部定义的变量
     
     注意:如果在函数内部定义和全局变量同名的变量,此时在函数内部,局部变量会暂时屏蔽全局变量的作用域
     */

    代码:

    #import <Foundation/Foundation.h>

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int m=100;
            __block int m2=111;
            
            void (^myBlock1)(void)=^(void){
    //            首先,在block变量的内部可以直接访问其外部的变量
                
    //            int m=200;
    //            其次,如果在block内部定义了与外部同名的变量,那么就会覆盖外部的变量
                
    //            m=300;
    //            我们无法直接修改外部的变量,上面一条语句是错误的
                
                m2=222;
    //            如果一定要在block变量的内部修改外部的变量值,那么要将外部定义的变量设置为__block类型(注意有两个下划线)
                NSLog(@"这是在block变量的内部   m=%d,m2=%d",m,m2);
            };
            myBlock1();
        }
        return 0;
    }


    ———————————————————————————————————————————
    block应用(1)

    日程表,大多数日程计划一致,只有少数不一致时应该怎么使用block

    代码:

    //用block变量作为函数的参数(可以做到重复输出的时候用block变量只更改需要更改的部分)
    #import <Foundation/Foundation.h>
    void daysDoThings(void (^dayBlock)())//将 一个无返回值、参数为一个 无返回值无参的block类型 的变量 传进去,这个地方定义传进来的block变量的类型名的时候可以随意
    {
        printf("--------------- ");
        printf("起床");
        printf("刷牙");
        
        dayBlock();
     
        printf("吃饭");
        printf("睡觉");
        printf(" ");
    }

    void daysDoThings222(int n)
    {
        typedef void (^newDaysBlock)();//定义一个block变量的新类型
        
        newDaysBlock work;//创建一个newDaysBlock类型的block变量work
        switch (n) {
            case 1:
                work=^{
                    printf("Day1");
                };
                break;
                
            case 2:
                work=^{
                    printf("Day2");
                };
                break;
                
            case 3:
                work=^{
                    printf("Day3");
                };
                break;
                
            case 4:
                work=^{
                    printf("Day4");
                };
                break;
                
            default:
                break;
        }
        daysDoThings(work);
    }

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
    //        方法①,我们要先创建好这些block类型的变量,然后传入函数进行调用
    //        void (^dayBlock1)()=^{
    //            printf("1");
    //        };
    //        daysDoThings(dayBlock1);
    //        
    //        void (^dayBlock2)()=^{
    //            printf("2");
    //        };
    //        daysDoThings(dayBlock2);
    //        
    //        void (^dayBlock3)();
    //        dayBlock3=^{
    //            printf("3");
    //        };
    //        daysDoThings(dayBlock3);
            
            
    //        方法②,我们可以直接在调用函数的同时传block变量
    //        
    //        daysDoThings(^{
    //            printf("5");
    //        });
            
    //        我们可以这样用是因为我们知道,一个block变量是这样定义的:
    //        void (^myBlock)();
    //        myBlock=^{ ...  };
    //        所以可以将block变量的定义部分传进函数里去
            
    //        方法③
            daysDoThings222(1);
            daysDoThings222(2);
            daysDoThings222(3);
            daysDoThings222(4);
        }
        return 0;
    }


    ★附加:用block作为函数的返回值学习完成之后,可以改上面的代码,我现在将改好的代码写在下面,读者学习完毕后可以回来看看。

    代码:

    #import <Foundation/Foundation.h>
    typedef void (^newBlockForDays)();

    void days(int day)//记住,block类型的变量名要括号括起来,并且定义block类型的变量的时候要加^
    {
        newBlockForDays setDays(int i);
        //引入setDays方法,不然没法用(函数声明部分)
        
        printf("****");
        
        //创建一个newBlockForDays的变量day1去接收setDays方法的返回值
        newBlockForDays day1;
        day1=setDays(day);
        
        //day1接收完值后就是一个具备返回值功能的block变量,所以可以直接调用这个block变量
        day1();
        printf("********** ");
    }

    newBlockForDays setDays(int i)
    //将这个方法改为返回值为block类型变量的方法
    {
        
        newBlockForDays workDay;
        switch (i) {
            case 1:
                workDay=^{
                    printf("Day11111");
                };
                break;//如果这里不写break,那么默认向下执行,那么workDay的值会一直改变,直到遇到break跳出程序,才终止了对workDay的赋值
            case 2:
                workDay=^{
                    printf("Day22222");
                };
                break;
            case 3:
                workDay=^{
                    printf("Day33333");
                };
                break;
            case 4:
                workDay=^{
                   printf("Day44444");
                };
                break;
            case 5:
                workDay=^{
                    printf("Day55555");
                };
                break;
                
            default:
                break;
        }
        return workDay;
    }



    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            days(1);
            days(2);
            days(3);
            days(4);
            days(5);
        }
        return 0;
    }



    ———————————————————————————————————————————
    block作为函数的返回值

    代码:

    #import <Foundation/Foundation.h>

    //创建一个新的block类型(返回值为int类型,并且含有两个参数)
    typedef int (^newBlock1)(int ,int );

    //创建一个返回值为newBlock1类型的函数test1  (test函数本身是没有参数的)
    newBlock1 test1()
    {
        //返回值为newBlock1类型,那么自然要先创建一个newBlock1类型的变量用来返回
        newBlock1 nb;
        
        //自然变量nb也应该拥有两个int类型的形参
        nb=^(int x,int y){
            return x>y?x:y;
        };
        //注意这里返回的是newBlock1类型的变量
        return nb;
    }

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            newBlock1 n1;
           n1=test1();//test1就是返回一个可以判断两个数的较大数的block变量,然后将这个具有这个功能的block变量给n1,这样n1就具备接收参数并判断大小的能力了(可以说每次调用无参函数test1,就生成一个具备相应功能的block类型的变量)   
         
    //        这样我们再输出n1(12,11) 此时的n1是接收了参数的n1,返回值为int类型
            NSLog(@"n1->max=%d",n1(12,11));

        }
        return 0;
    }


    //★上面的程序大家可能不是很理解,我觉得不理解的地方应该是不理解怎么调用的。我着重解释一下:
    //首先test1函数是一个返回值为newBlock1类型的无参函数,一定注意test1返回的是一个block类型的变量,而返回的这个block类型的变量是具备以下功能的————接收两个数字并判断两个数字大小,最后返回较大值。
    //接着在main函数中先创建一个newBlock1类型的变量n1去接受test1的返回值,这样n1就是一个具备上述功能的block类型的变量了。所以说我们可以给n1传值并输出n1的返回值



    ////       对于上面的程序,我们只是为了让block作为函数的返回值而写的,其实完全没有必要这样做,这样做显得非常的麻烦。我们可以直接这么写:

    //#import <Foundation/Foundation.h>
    //
    //int main(int argc, const char * argv[]){
    //    @autoreleasepool {

    //        typedef int (^newBlock2)(int x,int y);
    //        newBlock2 n2;
    //        n2=^(int x,int y){
    //            return x>y?x:y;
    //        };
    //        NSLog(@"n2->max=%d",n2(12,13));
    //    }
    //}


    ———————————————————————————————————————————
    block的使用技巧及其注意事项

    //block和函数的区别:
    //①定义方式不一样
    //②block是类型,函数就是函数
    //③函数不能嵌套定义,block可以嵌套定义
    //④block是一中数据类型,所以可以做函数的参数和返回值。函数则不可以(函数不可以做另外函数的参数,也不可以做另外函数的返回值)

    #import <Foundation/Foundation.h>

    void test(int (^block1)(int num1,int num2))//这里加num1 num2更好,因为这样调用test的时候提示更多
    {
        
    }

    int main()
    {
        @autoreleasepool {
            test(//test
                 ^int(int num1, int num2) {//注意这里的形式,多了一个int,注意注意注意!!!
                     
                     void (^myblock)()=^{// 随意嵌套定义的block变量
                         NSLog(@"QQQQQ");
                     };
                     myblock();
                     
                     return num1+num2;
                 }
                 );//test
        }
        return 0;
    }


    ———————————————————————————————————————————

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    soundtouch 变速算法matlab实现
    resample matlab实现
    hrtf virtual surround matlab实现
    hrtf 旋转音效matlab实现
    audio mixer
    schroeder reverb matlab实现
    HTML DOCTYPE文档类型举例说明
    window 连接双网
    linux 命令
    sqlserver 时间戳
  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787877.html
Copyright © 2011-2022 走看看