• Objective-C中的Block(基础)


    基本语法

    定义的语法格式:

    ^ [块返回值类型] (形参类型1 形参1, 形参类型2 形参2, ...){
        //块执行体
    }
    
    • 1
    • 2
    • 3

    定义块的语法与定义函数的语法存在如下差异:

    • 定义块必须以^开头;
    • 定义块的返回值类型可以省略;
    • 定义块无须指定名字;
    • 如果块没有参数,参数部分的括号不可省略,但可以留空,建议以void作为占位符。

    若需多次调用已经定义的块,可定义一个块变量,将该块赋给块变量,通过块变量来调用块。定义块变量的格式:

    块返回值类型 (^块变量名) (形参类型1, 形参类型2, ...);
    
    • 1

    块与匿名函数类似,块变量与函数指针类似。

    块与局部变量

    1. 对于没有用__block修饰的局部变量,块只能访问它,但不可修改它;且在定义块时就已经将这种局部变量的值保存在块中,而不是等到调用块时才去访问、获取它的值,因此,后续程序对局部变量的值的修改,对块没有影响,即便这种修改在调用块之前。
      #import <Foundation/Foundation.h>
      int main(){
          @autoreleasepool{
              int my = 20;
              void (^printMy)(void) = ^(void){
                  //尝试对局部变量赋值,程序会报错
                  my = 30; // ①
                  NSLog(@"%d", my); //访问局部变量是可以的
              };
              my = 45;
              printMy(); //调用块
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      将①处代码注释掉,再编译运行上述程序,会输出20,而非45。

    2. 对于__block修饰的局部变量,块内可以修改它;并且,无论何时,块都会直接使用该局部变量本身,而不是将局部变量的值复制到块内。
      #import <Foundation/Foundation.h>
      int main(int argc, char* argv[]){
          @autoreleasepool{
              __block int my = 20;    
              void (^printMy)(void) = ^(void){
                  NSLog(@"%d", my);
                  my = 30;
                  NSLog(@"%d", my);
              };    
              my = 45;
              printMy();
              NSLog(@"%d", my);
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

      上述程序三次分别输出45、30、30。

    块作为函数参数

    块作为函数参数时,无需定义块变量,直接把块作为参数传递给函数即可。出于可读性考虑,通常将块作为函数的最后一个参数。

    使用typedef定义块类型

    语法格式:

    typedef 块返回值类型 (^块类型)(形参类型1 [形参名], 形参类型2 [形参名], ...);
    
    • 1

    用途:

    1. 复用块类型,使用块类型可以更方便地定义块变量;
      #import <Foundation/Foundation.h>
      int main(int argc, char* argv[]){
          @autoreleasepool{
              //定义了一个返回类型为void、形参为NSString*的块类型FKPrintBlock
              typedef void (^FKPrintBlock)(NSString*);
              //使用块类型定义块变量,并将指定块赋给块变量
              FKPrintBlock print = ^(NSString* info){
                  NSLog(@"%@", info);
              };
              //使用块类型定义块变量,并将指定块赋给块变量
              FKPrintBlock loopPrint = ^(NSString* info){
                  for(int i = 0; i < 3; ++i){
                      NSLog(@"%@", info);
                  }
              };
              //一次调用两个块
              print(@"Objective-C");
              loopPrint(@"iOS");
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
    2. 使用块类型定义函数参数。
      #import <Foundation/Foundation.h>
      typedef void (^FKProcessBlock)(int); //定义一个块类型
      //使用FKProcessBlock定义最后一个参数类型为块
      void processArray(int array[], unsigned int len, FKProcessBlock process){
          for(int i = 0; i < len; ++i){
              //将数组元素作为参数调用块
              process(array[i]);
          }
      }
      int main(int argc, char* argv[]){
          @autoreleasepool{
              int arr[] = {2, 4, 6};
              //传入块作为参数调用processArray()函数
              processArray(arr, 3, ^(int num){
                  NSLog(@"元素平方为:%d", num * num);
              });
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
  • 相关阅读:
    Python 越来越火爆
    vue的第2篇 开发环境vscode的安装以及创建项目空间
    僵尸扫描实战
    基于C#的房屋租赁管理系统设计与实现
    蓝桥杯官网练习题(回文日期)
    面试计算机网络八股文十问十答第九期
    【X806开发板试用】串口数据透传阿里云IOT
    【算法刷题-栈与队列篇】
    AQS之ReentrantLock分析 (四)
    2022最新PPT模板,免费下载
  • 原文地址:https://blog.csdn.net/qq_29186859/article/details/126039246