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("---------------\n");

    printf("起床");

    printf("刷牙");

    

    dayBlock();

 

    printf("吃饭");

    printf("睡觉");

    printf("\n");

}



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("**********\n");

}



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;

}





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

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

上一篇:volatile可见性和指令重排


下一篇:Action向视图传值的6种方式(转)