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;
}
原文地址:https://www.cnblogs.com/kongweiiwei/p/4686581.html