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;
}


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

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

转载于:https://www.cnblogs.com/wzy294250051/p/4787877.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值