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

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;

}





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

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

C 【block类型全方位详解】的更多相关文章

  1. Scala 深入浅出实战经典 第54讲:Scala中复合类型实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  2. Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  3. JS类型转换规则详解

    JS类型转换规则详解 一.总结 一句话总结:JS强制类型转换中的类型名强制类型转换和其它语言不同,是类型类的构造方法,Number(mix) 一句话总结(JS类型本质):因为js是弱类型语言,所以它相 ...

  4. Struts2中 Result类型配置详解

    一个result代表了一个可能的输出.当Action类的方法执行完成时,它返回一个字符串类型的结果码,框架根据这个结果码选择对应的result,向用户输出.在com.opensymphony.xwor ...

  5. 干货 | Elasticsearch Nested类型深入详解(转)

    https://blog.csdn.net/laoyang360/article/details/82950393 0.概要在Elasticsearch实战场景中,我们或多或少会遇到嵌套文档的组合形式 ...

  6. 干货 | Elasticsearch Nested类型深入详解

    在Elasticsearch实战场景中,我们或多或少会遇到嵌套文档的组合形式,反映在ES中称为父子文档. 父子文档的实现,至少包含以下两种方式: 1)父子文档 父子文档在5.X版本中通过parent- ...

  7. javaScript对象-基本包装类型的详解

    本人按书上的内容大致地把javaScript对象划分成“引用类型”.“基本包装类型”和“内置对象”三块内容. 我们这篇先了解下基本包装类型的详细用法吧! 一.我们先解下相关概念: 1.引用类型的值(对 ...

  8. Redis全方位详解--数据类型使用场景和redis分布式锁的正确姿势

    一.Redis数据类型 1.string string是Redis的最基本数据类型,一个key对应一个value,每个value最大可存储512M.string一半用来存图片或者序列化的数据. 2.h ...

  9. 匹夫细说C#:可以为null的值类型,详解可空值类型

    首先祝大家中秋佳节快乐~ 0x00 前言 众所周知的一点是C#语言是一种强调类型的语言,而C#作为Unity3D中的游戏脚本主流语言,在我们的开发工作中能够驾驭好它的这个特点便十分重要.事实上,怎么强 ...

随机推荐

  1. .NET程序性能的基本要领

    前几天在老赵的博客上看到,Bill Chiles (Roslyn 编译器的Program Manager)写了一篇文章叫做<Essential Performance Facts and .NE ...

  2. 模拟log4j获取日志对象调用所在的类名、方法名及行号

    当我们在记录日志时,每个类中会定义一个日志对象,然后利用这个对象去写日志,那么我们在处理日志时,如何能才能记录日志对象所在的类.方法和行号呢?log4j中已经实现了该功能,那么它是怎么实现的呢? 其实 ...

  3. 关于android 图像格式问题

    这算是篇总结吧.6月份开始做的一个android上的ar项目结束了.我做的部分是二维码识别和图像识别的预处理.这个项目虽然很累,但是让我学到了很多东西,特别是严格的编码规则,和java代码的效率优化, ...

  4. 推荐资料——最受网友力荐的30份HTML前端开发资料

    w3cmark最近会新增一个栏目,专注于搜集前端资源的下载,包括和前端相关的电子书.文档PPT.手册.视频教程等等.而下载的媒介是用微博的微盘,至于为什么选择微盘的,那是因为和微博关联起来,通过微盘上 ...

  5. Android Studio中导入第三方库

    之前开发Android都是使用的eclipse,近期因为和外国朋友Timothy一起开发一款应用,他是从WP平台刚切换使用Android的,使用的开发环境时Android Studio,为了便于项目的 ...

  6. Java HttpClient使用小结

    httpclient是apache的一个项目:http://hc.apache.org/ 文档比較完好:http://hc.apache.org/httpcomponents-client-ga/tu ...

  7. IOS编程之相机和相册

    概述 IOS设备中的相机和相册,是我们在项目开发中经常会使用到的多媒体元素,使用相机可以获得最新想要的照片,而使用相册则可以访问IOS设备中的图片资源 使用IOS设备中的相机/相册获得图片资源 是否允 ...

  8. 用systemtap对sysbench IO测试结果的分析1

    http://www.actionsky.com/docs/archives/171  2016年5月6日  黄炎 近期在一些简单的sysbench IO测试中, 遇到了一些不合常识的测试结果. 从结 ...

  9. 提升GDI画图的效率

    假设我们要画一个坐标图,里面可能还需要画网络线.XY各个单位的值.曲线或直线等,可能的函数代码如下: void OnPaint () { CPaintDC dc (this); DrawXY (&am ...

  10. mysql官方示例数据库

    employees数据库:http://ari.iteye.com/blog/1066690  https://launchpad.net/test-db/employees-db-1/1.0.6