zoukankan      html  css  js  c++  java
  • block的概念及基本使用 /block访问外部变量

    block的概念及基本使用 

    block 是实质上是代码段,但它不像方法有方法名,所以就定义一种block类型来接收

    block
    
    * block是一种数据类型, 可以使用这种数据类型定义变量, 并赋值。
    * block数据类型在使用前需要先定义该数据类型, 然后再使用(就像使用Person类一样, 先 定义一个Person类, 然后再通过Person类声明一个Person类型变量)。

    * block这种数据类型用来保存一个方法、函数、一段代码

    * 必须掌握: block的定义语法、使用场景

    * 使用inlineBlock辅助编写block代码

    //int (^block)(int,int) = ^(int n, int m){}; int (^block)(int,int) = ^(int n, int m){};

    block的typedef 形式和函数指针的用法很像,先来回顾下
    1、函数指针回顾

     

    int (*p)(int x,int y); //其中p是函数指针变量名,这个p指针的含义是它只能指向返回值是int型,有二个参数,而且参数是int型的函数
    用法:p = sum;
    p = jian;                    //方法名本身存放的就是地址,所以不用取地址,所以p可以指向上面 jia jian  chen chu 四个函数,是不是很省事
    调用:p(2,3);           //其实你写成(*p)(2,3)也不会报错。*p就是这个地址
    2)函数指针别名
    
    typedef
    int (*NewType)(int x,int y); NewType f1,f2,f3; //f1实际类型 int (*f1)(int x,int y);


    加了typedef,
    NewType这就不是一个函数指针,而是一个新的类型,它定义了f1,f2,f3三个NewType类型的数据,他们指向的是它只能指向返回值是int型,有二个参数,而且参数是int型的函数

    实际的用途就是简化函数定义的书写

    
    
    2、block的typedef
    
    利用typedef定义block类型(和指向函数的指针很像)
    格式: typedef 返回值类型 (
    ^新别名)(参数类型列表);
    Typedef
    int(^MyBlock)(int ,int);

    block访问外部变量 

    这里说明了二个问题很重要的问题


    1: block内部可以访问外部值的问题,但是注意,这是一个新的内存空间变量 

    2: 在block内部不可以修改block外部的变量 


    #import <Foundation/Foundation.h>
    /**
     *  block内部访问外部值的问题
     *  block内部不允许修改外部变量值
     */
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
        int m = 10;
        
        NSLog(@"1:m = %d",m);   //10
        NSLog(@"2:m addr = %p",&m);         //栈区
      //定义变量,并且赋值
        //当定义block的时候,block会把外部变量以const的方式(常量)复制一份
        //存放到block的所在的内存中
        void (^myBlock)()=^{
            //m的值不能被修改
            //m = 100;
            
            NSLog(@"5:m addr = %p",&m);     //堆区
            //可以访问m的值
            NSLog(@"3:in block m = %d",m); 
            
        };
        
    NSLog(
    @"4:m addr = %p",&m); //栈区 //使用 myBlock(); } return 0; }
    2015-07-29 16:46:54.865 3-【掌握】block访问外部变量[868:146191] 1:m = 10
    2015-07-29 16:46:54.866 3-【掌握】block访问外部变量[868:146191] 2:m addr = 0x7fff5fbff6ec
    2015-07-29 16:46:54.866 3-【掌握】block访问外部变量[868:146191] 4:m addr = 0x7fff5fbff6ec
    2015-07-29 16:46:54.866 3-【掌握】block访问外部变量[868:146191] 5:m addr = 0x100300120
    2015-07-29 16:46:54.866 3-【掌握】block访问外部变量[868:146191] 3:in block m = 10
    3: 默认情况下,Block内部不能修改外部的局部变量 ,但可以在块内重新定义m,此时定义的m在栈区,可以说局部变量屏蔽了相对的全局变量


    4:
    给局部变量加上__block关键字,则这个局部变量可以在block内部进行修改,不再以const的方式拷贝

    5:用了__block后,以后使用的都是block里面堆区的变量 m
     
    #import <Foundation/Foundation.h>

    n=0; int main(int argc, const char * argv[]) { @autoreleasepool { __block int m = 10; NSLog(@"1:m add = %p",&m); //栈区地址 //__block 不在以const的方式拷贝 void (^myBlock)()=^{ //m的值不能被修改 m = 100; //堆区的m被修改成100 // n = 10; //全局变量可以直接修改 // int m = 100; //默认情况下,Block内部不能修改外部的局部变量 ,但可以在块内重新定义m,此时定义的m在栈区
                NSLog(@"5:m addr = %p",&m);     //堆区
                //可以访问m的值
                NSLog(@"3:in block m = %d",m);  // ?
            
            };
           
    myBlock(); NSLog(
    @"6:m = %d",m); // 100 //用了__block后,以后使用的都是block里面堆区的变量 m NSLog(@"7:m addr = %p",&m); } return 0; }
    2015-07-29 16:59:28.018 3-【掌握】block访问外部变量[878:150305] 1:m add  = 0x7fff5fbff708
    2015-07-29 16:59:28.019 3-【掌握】block访问外部变量[878:150305] 5:m addr = 0x1001205d8
    2015-07-29 16:59:28.019 3-【掌握】block访问外部变量[878:150305] 3:in block m = 100
    2015-07-29 16:59:28.019 3-【掌握】block访问外部变量[878:150305] 6:m = 100
    2015-07-29 16:59:28.020 3-【掌握】block访问外部变量[878:150305] 7:m addr = 0x1001205d8

    4-【理解】应用:block的使用场景1 

    #import <Foundation/Foundation.h>
    
    //void (^workBlock)()
    // block类型的变量 workBlock
    // 作为函数的参数
    void work(void (^workBlock)()){                      //思路代码你发现每天不一样的就一处   ,那只有block才能传代码块
        
        NSLog(@"起床");
        NSLog(@"刷牙");
        NSLog(@"去车站");
        NSLog(@"坐车");
        
    //    NSLog(@"了解项目"); //思考: 把这句话作为参数传递过来
        workBlock();
        
        
        NSLog(@"去车站");
        NSLog(@"坐车回家");
        NSLog(@"吃饭");
        NSLog(@"睡觉");
    }
    
    //每天做什么事情
    void workDay(int n){
        
        // 定义别名
        typedef void (^workBlock) ();
        workBlock w;  //w是变量
        
        switch (n) {
            case 1:
                w =^{
                    
                    NSLog(@"----->了解项目");
                    
                };
                break;
                
            case 2:
                w = ^{
                    
                    NSLog(@"----->分析项目");
                    
                };
                break;
                
            case 3:
                w = ^{
                    
                    NSLog(@"----->写项目");
                    
                };
                break;
                
            case 4:
                w = ^{
                    
                    NSLog(@"----->调试项目");
                    
                };
                break;
            case 5:
                w = ^{
                    
                    NSLog(@"----->离职");
                    
                };
                break;
                
            default:
                break;
        }
        
       //调用work函数
        work(w);
    
    
    }
    
    //void day1(){
    //
    //     NSLog(@"起床");
    //     NSLog(@"刷牙");
    //     NSLog(@"去车站");
    //     NSLog(@"坐车");
    //    
    //     NSLog(@"了解项目");
    //    
    //     NSLog(@"去车站");
    //     NSLog(@"坐车回家");
    //     NSLog(@"吃饭");
    //     NSLog(@"睡觉");
    //}
    //
    //void day2(){
    //    
    //    NSLog(@"起床");
    //    NSLog(@"刷牙");
    //    NSLog(@"去车站");
    //    NSLog(@"坐车");
    //    
    //    NSLog(@"分析项目");
    //    
    //    NSLog(@"去车站");
    //    NSLog(@"坐车回家");
    //    NSLog(@"吃饭");
    //    NSLog(@"睡觉");
    //}
    //
    //
    //void day3(){
    //    
    //    NSLog(@"起床");
    //    NSLog(@"刷牙");
    //    NSLog(@"去车站");
    //    NSLog(@"坐车");
    //    
    //    NSLog(@"写代码");
    //    
    //    NSLog(@"去车站");
    //    NSLog(@"坐车回家");
    //    NSLog(@"吃饭");
    //    NSLog(@"睡觉");
    //}
    //
    //
    //void day4(){
    //    
    //    NSLog(@"起床");
    //    NSLog(@"刷牙");
    //    NSLog(@"去车站");
    //    NSLog(@"坐车");
    //    
    //    NSLog(@"调试程序");
    //    
    //    NSLog(@"去车站");
    //    NSLog(@"坐车回家");
    //    NSLog(@"吃饭");
    //    NSLog(@"睡觉");
    //}
    //
    //void day5(){
    //    
    //    NSLog(@"起床");
    //    NSLog(@"刷牙");
    //    NSLog(@"去车站");
    //    NSLog(@"坐车");
    //    
    //    NSLog(@"离职");
    //    
    //    NSLog(@"去车站");
    //    NSLog(@"坐车回家");
    //    NSLog(@"吃饭");
    //    NSLog(@"睡觉");
    //}
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
    //        day1();
    //        day2();
    //        day3();
    //        day4();
    //        day5();
            for (int i=1; i<=5; i++) {
                workDay(i);
            }
            
            
        }
        return 0;
    }

    block作为函数的返回值 

    返回的是一个类型,那你必须是是哥类型,所以必须用到typedef,定义一个新类型
    #import <Foundation/Foundation.h>
    //返回值是block类型的
    //void (^block)();
    //定义新的block类型
    //1) 使用 typedef 定义一个新的类型
    typedef void (^newType)();
    
    //block类型作为函数的返回值
    //2) 用新定义的类型作为函数的返回值
    newType test(){
        //定义block变量
        newType w1 = ^{              //定义一个newType类型的变量w1用来接收block代码块
        
            NSLog(@"xxxxx");
            NSLog(@"hello world");
        };
    
        return w1;  //返回值block
    
    }
    
    //重新定义了一个新的类型 newType2
    typedef int(^newType2)(int ,int );
    newType2 test2(){
    
        //返回一个特殊的"值" 这个值是一个有返回值,有两个参数的的代码块
        return ^(int a,int b){            //相当于把一个代码块返回给了n2
    
            return  a+b;
        };
    
    }
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            
            //定义block类型的变量
            //3) 定义block变量接收 函数返回的结果
            newType n1 = test();       // 定义一个newType类型的变量n1用来接收返回值w1,我

    //4) 执行block
             n1();                 //这个例子完全看不出这个定义函数的优势和作用
            /*
             n2 =^(int a,int b){      
             
             return  a+b;
             };
                   
             */
            newType2 n2 = test2();
            //调用block
            int s =  n2(23,12);
            
    NSLog(
    @"s = %d",s); } return 0; }
    【总结】代码块定义的本身就比较怪异,导致它的扩展方法也不是容易记,可能这需要一个熟悉的过程

    应用:block的使用场景2 

    思考&实现1:
    用返回值是block的函数,修改我们应用场景的代码
    #import <Foundation/Foundation.h>
    //void (^workBlock)()
    // block类型的变量 workBlock
    // 作为函数的参数
    // 给无参无返回值的block起个别名(新的类型)
    typedef void(^blockType)();
    
    void work(int n){
        
        NSLog(@"起床");
        NSLog(@"刷牙");
        NSLog(@"去车站");
        NSLog(@"坐车");
        
        //    NSLog(@"了解项目"); //思考: 把这句话作为参数传递过来
        //workBlock();
        
        //声明 workDay这个函数
        blockType workDay(int n);
        blockType w = workDay(n);
        w();
        
        
        NSLog(@"去车站");
        NSLog(@"坐车回家");
        NSLog(@"吃饭");
        NSLog(@"睡觉");
    }
    
    //每天做什么事情
    blockType workDay(int n){
    
        blockType w;  //w是block变量
        
        switch (n) {
            case 1:
                w =^{
                    
                    NSLog(@"----->了解项目");
                    
                };
                break;
                
            case 2:
                w = ^{
                    
                    NSLog(@"----->分析项目");
                    
                };
                break;
                
            case 3:
                w = ^{
                    
                    NSLog(@"----->写项目");
                    
                };
                break;
                
            case 4:
                w = ^{
                    
                    NSLog(@"----->调试项目");
                    
                };
                break;
            case 5:
                w = ^{
                    
                    NSLog(@"----->离职");
                    
                };
                break;
                
            default:
                break;
        }
        
        //返回值是block类型的
        return w;
        
        
    }
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            for (int i=1; i<=5; i++) {
                work(i);
            }
    
        }
        return 0;
    }
  • 相关阅读:
    [日常训练]大灾难
    [cf235D]Graph Game
    [日常训练]选课
    [日常训练]挂科
    [学习笔记]概率&期望
    [日常训练]yayamao的神题
    [学习笔记]原根
    LOJ#2132. 「NOI2015」荷马史诗
    LOJ#2131. 「NOI2015」寿司晚宴
    LOJ#2129. 「NOI2015」程序自动分析
  • 原文地址:https://www.cnblogs.com/kongweiiwei/p/4686581.html
Copyright © 2011-2022 走看看