zoukankan      html  css  js  c++  java
  • 深入学习block

    首先,什么是block?block其实就是一个代码块,把你想要执行的代码封装在这个代码块里,等到需要的时候再去调用。那block是OC对象吗?答案是肯定的。

    做一道很简单的关于block的测试题:

    int (^testBlock)
       (int) = ^(int num) {
          return num++;
        };
        NSLog(@"%d", testBlock(testBlock(testBlock(3))
    ));

    这道题是我公司面试题中的一道,来面试的都是至少两年工作经验的,但是很郁闷,这道题绝大多数人写的都是6。。正确结果为:3。

    以下讲解的内容均是ARC环境下。

     

    一、block的分类

    • NSStackBlock:栈block

    • NSMallocBlock:堆block

    • NSGlobalBlock:全局block

    1.NSStackBlock:

    特点:生命周期由系统控制,函数返回即销毁

    用到局部变量、成员属性变量,且没有强指针引用的block都是栈block

    int (^testBlock)
       (int) = ^(int num) {
          return num++;
        };
        NSLog(@"%d", testBlock(testBlock(testBlock(3))
    ));

    注意:不是没有强指针(copy或strong)引用的block,就是栈block,也有可能是全局block(下面会介绍什么是全局block)。

    2.NSMallocBlock:

    特点:没有强指针引用即销毁,生命周期由程序员手动管理
    栈block如果有强指针引用或copy修饰的成员属性引用就会被拷贝到堆中,变成堆block

    //堆block
     int j = 0;    
     void(^mallocBlock)() = ^ {
            NSLog(@"%d",j);
        };
        NSLog(@"%@",mallocBlock);
    //输出结果 <__NSMallocBlock__: 0x7f8cd351db80>

    上面代码也没用看到strong 或 copy修饰符,但是为什么会强引用的,因为在ARC环境下,我们在声明变量的时候,前面是会被默认加上 __strong 修饰符的。所以我们在ARC下声明的Block一般都是堆block。

    3.NSGlobalBlock: 

    特点:命长,有多长?很长很长,人在塔在(应用程序在它就在)

    没有用到外界变量,或者只用到全局变量、静态(static)变量的block就是全局block

    对于全局block,用weak,strong,还是copy修饰都是可以的。(但最好不用用weak)

    //全局block
        void (^globalBlock) () = ^ {
            NSLog(@"%d",staticNum);
        };
        NSLog(@"%@",globalBlock); 
    //输出结果 <__NSGlobalBlock__: 0x108152110>

    注意:如果block中没有用到外界变量,不管他是用什么修饰符修饰,他都是全局block!

    例如:

    void (^global2Block) () = ^ {
            NSLog(@"globalBlock");
        };
        NSLog(@"%@",global2Block); // 输出结果 <__NSGlobalBlock__: 0x1023a0150>

    二、block对外界变量的捕获

    1.1 基本数据类型:局部变量

         block会拷贝该变量的值当做常量使用,外界修改变量的值不会影响block内部,且block内部不能对其修改

         block内部修改外界变量i的值直接报错,如果想要修改,可以在int a = 0前面加上关键字__block,此时i等效于全局变量或静态变量

    int a = 0;   
        void (^block1)() = ^ { 
            NSLog(@"a = %d",a);
        };
        a++;
        block1(); //输出结果 a = 0;    
        __block int b = 0;   
        void (^block2) () = ^ {
            NSLog(@"b = %d",b); // 输出结果 b = 0;
            b = 2;
        };
        block2();
        NSLog(@"b = %d",b); //输出结果 b = 2;

    1.2 基本数据类型:成员变量(实例变量),静态变量,全局变量

       block直接访问变量地址,在block内部可以修改变量的值,并且外部变量被修改后,block内部也会跟着变

    self.num = 1;
    self.num ++;  
    
    void (^block3) () = ^ {
            self.num++;
    };
    block3();
    NSLog(@"%d",self.num);
    //输出结果为 3

     2.1 指针类型: 局部变量

         block会复制一份指针并强引用指针所指对象,且内部不能修改指针的指向,但是可以修改指针所指向对象的值

    NSMutableString *str = @"abc".mutableCopy; 
         void (^block4) () = ^ { 
    //        str = @"def"; 报错
          [str appendString:@"def"];
          NSLog(@"str = %@",str);
        };
        str = @"123".mutableCopy;
        block4(); //输出结果为 "adbdef"

    2.2 指针类型: 成员变量(实例变量),静态变量,全局变量

         block不会复制指针,但是会强引用该对象,内部可修改指针指向,block会强引用成员属性变量所属的对象,这也是为什么block内部用到self.xxx_xxx可能会引起循环引用的原因

    static NSString *staticStr = @"abc";  
      void (^block5) () = ^ {
            NSLog(@"staticStr = %@",staticStr);
            staticStr = @"def";
            NSLog(@"staticStr = %@",staticStr);
        };
        staticStr = @"123";
        block5();    
    
    //输出结果为 staticStr = 123  staticStr = def
  • 相关阅读:
    使用DBUtils获取Blob类型数据
    关于 JupyterLab 与 Pandas 资源整理
    关于 Conda 在 MacOS Catalina 环境变量问题
    推荐一个符合 OIDC 规范的 JAVA 客户端
    关于 Chrome 的 Kiosk 模式
    Kubernetes 中的服务发现与负载均衡
    Prometheus 监控领域最锋利的“瑞士军刀”
    CD 基金会、Jenkins、Jenkins X、Spinnaker 和 Tekton 的常问问题
    Installing on Kubernetes with NATS Operator
    升级 ASP.NET Core 3.0 设置 JSON 返回 PascalCase 格式与 SignalR 问题
  • 原文地址:https://www.cnblogs.com/fengmin/p/5441331.html
Copyright © 2011-2022 走看看