一、Block是什么?

1. 是代码段,苹果推荐的类型,效率高,在运行中保存代码。用来封装和保存代码,有点像函数,block可以在任何时候执行;

2. 代码块本质上是和其他变量类似。不同的是,代码块存储的数据是一个函数体。使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值。

脱字符(^)是块的语法标记。按照我们熟悉的参数语法规约所定义的返回值以及块的主体(也就是可以执行的代码)。

   定义代码块语法:

  块类型   块对象  =  ^(参数列表){  夸函数体   };

void(^myblock)() = ^(){  // 无返回值 无参数 =右边的()可以省略
        NSLog(@"-------");
        NSLog(@"-------");
    };
    
int (^sumblock)(int, int) = ^(int a, int b) {  // 有返回值 有参数
        return a + b;
    };


  

下图是如何把块变量赋值给一个变量的语法讲解


    按照调用函数的方式调用块对象变量就可以了:


3. 和函数的相似性:

int result = 
myBlock(4); // result是 28

    1)可以保存代码;

    2)有返回值

    3)有形参

    4)调用方式一样

4. 标识符:^

二、基本使用

1. 定义block变量

有参数,返回值类型为int

;//无参数,返回值类型为空

2. 利用block封装代码

// 利用block封装代码
        // 1.接受两个参数
        int (^MyBlock1)(int, int) = ^(int a, int b) {
            return a + b;
        };
        
        // 2.无参数形式
        int (^MyBlock2)() = ^() {
            return 20;
        };
        
        // 3.无参数的省形式
        // 2.无参数形式
        int (^MyBlock3)() = ^ {
            return 20;
        };

3. Block

访问外部变量


内部可以访问外部变量;

Block内部不能修改外部的局部变量

__block关键字(两个下划线哦),则这个局部变量可以在block内部进行修改。

如:

void test2() {
    __block int c = 19;
    
    // 声明一个block变量
    // 可以使用无数多个变量进行调用
    MySum sum = ^(int a, int b) {
        // 如果外部的变量已经用__block关键字修饰,就可以在block内部修改这一个变量
        c = 19;
        return  a + b;
    };
    NSLog(@"%i", sum(10, 10));
}

4. 利用

typedef 定义 block 类型 ( 和指向函数的指针很像 )。关于tepedef的作用后面的的文章有介绍typedf讲解

    Typedef int(^MyBlock)(int , int);

block变量了。----使用这个好处就是:可以使用无数多个变量进行调用(如下面定义了两个变量),传统的方式只能定义一个变量

    MyBlock a, b; 

    a = ^(int a,int b){return a-b;};

    MyBlock b2 = ^(int n1,int n2){return n1*n2;}

三、拓展案例

1. 参数是NSString* 的代码块

void (^print)(NSString *x);
        print = ^(NSString *str){
            NSLog(@"print:%@", str);
        };
        
        print(@"Hello World");

2. 代码在字符串数组排序

// 字符串
        NSArray *str = [NSArray arrayWithObjects:@"abc 1", @"abc 22", @"abc 13", @"abc 0", @"abc 09", nil];
        NSComparator sort = ^(id str1, id str2) {
            return [str1 compare:str2];
        };
        
        NSArray *sortArray = [str sortedArrayUsingComparator:sort];
        NSLog(@"sortArray:%@", sortArray);

结果是:


@class关键字[598:144356] sortArray:( 

     "abc 0", 

     "abc 09", 

     "abc 1", 

     "abc 13", 

     "abc 22" 

 )


3. 代码块要想递归调用,代码快变量必须要是全局变量或者是静态变量,这样程序启动的时候代码块变量就初始化了,就可以递归调用

static void (^ const blocks)(int) = ^(int i)  
{  
    if (i > 0) {  
        NSLog(@"num:%d", i);  
        blocks(i - 1);  
    }  
};  
blocks(3);

4.在代码块中使用局部变脸和全局变量

int global = 1000;  
int main(int argc, const char * argv[])  
 {  
      @autoreleasepool {  
         void(^block)(void) = ^(void)  
         {  
            global++;  
             NSLog(@"global:%d", global);  
         };  
         block();  
         NSLog(@"global:%d", global);  
     }  
     return 0;  
 }

局部变量要想再代码块中能够更改的话需要在block里面添加一个__(两个下划线)