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

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. ecmall widgets 挂件开发详解

    Ecmall挂件开发 实质上是后台开发很多页面,分别去调用程序展示这些页面,达到首页内容更换很快的目的,这样做减少后续开发,开发人员只需开发挂件就可以了,至于位置可随意定.(还需调整html,但是起码 ...

  2. 【机器学习算法-python实现】决策树-Decision tree(1) 信息熵划分数据集

    (转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景 决策书算法是一种逼近离散数值的分类算法,思路比較简单,并且准确率较高.国际权威的学术组织,数据挖掘国际 ...

  3. Approaching the Fun Factor in Game Design

    I recently did some research on this and talked to Dr. Clayton Lewis (computer Scientist in Residenc ...

  4. Deep Learning(深度学习)学习笔记整理系列之(五)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

  5. Android应用集成支付宝接口的简化

    拿到支付宝接口的andriod demo后有点无语,集成一个支付服务而已,要在十几个java类之间引用来引用去,这样不仅容易导致应用本身代码结构的复杂化,调试起来也很累,于是操刀改造之: 该删的删,该 ...

  6. cocos2d-x jsbinding 在线更新策略设计

    在线更新是用脚本编写游戏逻辑的特有功能,由于脚本语言是边解释边编译的特性,使得游戏在运行的时候可以通过下载最新的脚本来执行游戏逻辑.在不修改Native接口的情况下,在线更新每次更新只需要下载一个(5 ...

  7. Linux开机执行顺序

      1. 加载 BIOS 的硬件信息,并取得第一个开机装置的代号: 2. 读取第一个开机装置的 MBR 的 boot Loader (亦即是 lilo, grub 等等) 的开机信息: 3. 加载 K ...

  8. CGI,FastCGI,PHP-CGI与PHP-FPM(转)

    http://www.cnblogs.com/zl0372/articles/php_4.html CGI CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服 ...

  9. Javascript实现鼠标框选元素后拖拽被框选的元素

    之前需要做一个框选元素后拖拽被框选中的元素功能,在网上找资料做了一些修改,基本达到了需要的效果,希望对也需要实现框选后拖拽元素功能的人有用. 页面加载后效果 框选后的内容可以拖拽,如下图: 代码下载

  10. 终端I/O之综述

    终端I/O有两种不同的工作模式: 规范模式输入处理(Canonical mode input processing).在这种模式中,终端输入以行为单位进行处理.对于每个读要求,终端驱动程序最多返回一行 ...