• block 的演练和使用


    概念

    • block 是 C 语言的
    • 是一种数据类型,可以当作参数传递
    • 是一组预先准备好的代码,在需要的时候执行
    • 动画 block 回顾

      self.demoView.center = CGPointMake(self.view.center.x, 0);
      // 此方法会立即执行动画 block
      [UIView animateWithDuration:2.0 delay:0 usingSpringWithDamping:0.3 initialSpringVelocity:10 options:0 animations:^{
          NSLog(@"动画开始");
          self.demoView.center = self.view.center;
      } completion:^(BOOL finished) {
          // 会在动画结束后执行
          NSLog(@"动画完成");
      }];
      NSLog(@"come here");

      block 基本演练

      • 最简单的 block
        - (void)blockDemo1 {
        
            // 定义block
            // 类型 变量名 = 值
            void (^block)() = ^ {
                NSLog(@"Hello block");
            };
        
            // 执行
            block();
        }

        使用 inlineBlock 可以快速定义 block,不过 block 一定要过关

      • 当作参数传递
        - (void)blockDemo2 {
            void (^block)() = ^ {
                NSLog(@"Hello block");
            };
        
            [self demoBlock:block];
        }
        
        ///  演示 block 当作参数传递
        - (void)demoBlock:(void (^)())completion {
            NSLog(@"干点什么");
        
            completion();
        }
      • 使用局部变量
        - (void)blockDemo3 {
            // 栈区变量
            int i = 10;
            NSLog(@"%p", &i);
        
            void (^block)() = ^ {
                // 定义 block 的时候会对栈区变量进行一次 copy
                NSLog(@"Hello block %d %p", i, &i);
            };
        
            [self demoBlock:block];
        }

        如果 block 中使用了外部变量,会对外部变量做一次 copy

      • 在 block 中修改外部变量
        - (void)blockDemo4 {
            // 栈区变量
            __block int i = 10;
            NSLog(@"%p", &i);
        
            void (^block)() = ^ {
                // 定义 block 的时候会对栈区变量进行一次 copy
                NSLog(@"Hello block %d %p", i, &i);
                i = 20;
            };
        
            NSLog(@"block 定义完成 %p %d", &i, i);
        
            [self demoBlock:block];
        
            NSLog(@"===>%d", i);
        }

        如果要在 block 内部修改栈区变量,需要使用 __block 修饰符,并且定义 block 之后,栈区变量的地址会变化为堆区地址block 的内存位置

        block 的内存位置

      •      全局区:如果block中没有使用任何全局变量
        • 栈区:如果 block 中使用了外部变量
          • MRC 模式可以看到
          • ARC 模式,系统会自动将 Block 复制到堆中
        • 堆区:将 block 设置给 copy 属性
          @property (nonatomic, copy) void (^myBlock)();
          - (void)blockDemo5 {
              int i = 10;
              void (^block)() = ^ {
                  NSLog(@"i --- %d", i);
              };
          
              NSLog(@"%@", block);
          
              self.myBlock = block;
          }
          
          - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
          
              NSLog(@"%@", self.myBlock);
          }

          注意:虽然目前 ARC 编译器在设置属性时,已经替程序员复制了 block,但是定义 block时,仍然建议使用 copy 属性

          // 面试题
          - (void)blockDemo4 {
              int i = 10;
              
              // 提问:输出是几?
              // 10,定义 block 的时候,10已经被复制到堆中了
              void (^block)() = ^ {
                  NSLog(@"%d", i);
              };
              
              i = 20;
              
              block();
          }

          问:block在哪里?=> 全局区

          - (void)blockDemo5 {
              // 问:block在哪里?=> 全局区
              // 原因:block 中没有使用任何的外部变量,不会因为任何外部因素而改变
              // 会保存在全局区
              void (^block)() = ^ {
                  NSLog(@"hello world");
              };
              NSLog(@"%@", block);
          }

          问:block在哪里?=> 堆区

          - (void)blockDemo6 {
              int i = 10;
              // 问:block在哪里?=> 堆区
              // 原因:因为用到了外部变量,而block准备好的代码,在`需要的时候`被执行
              // 调用方并不知道 block 什么时候会被调用
              // MRC 开发,block 在栈区,因为 MRC 的所有内存管理由程序员负责
              // ARC 开发,block 之所以在堆区,是因为编译器帮我们实现的
              // 问:为什么block属性要用 copy?
              void (^block)() = ^ {
                  NSLog(@"hello %d", i);
              };
              NSLog(@"%@", block);
              
              // 在定义 block 属性的时候,必须使用 copy,这样在设置数值的时候,可以将栈区的 block 复制到堆中
              self.myBlock = block;
              
              NSLog(@"%@", self.myBlock);
          }
        • 总结
        • Block 如果里边没有引用外边的任何变量,在全局区
        • Block 如果里边引用外边的任何变量,在堆区
        • MRC 的 Block 在栈区
        • ARC 的 Block 在堆区
  • 相关阅读:
    JQuery制作网页——第五章 初识 jQuery
    JQuery制作网页—— 第四章JavaScript对象及初识面向对象
    JQuery制作网页—— 第三章 JavaScript操作DOM对象
    JQuery制作网页—— 第二章 JavaScript操作BOM对象
    JQuery制作网页—— 第一章 JavaScript基础
    JAVA / MySql 编程——第八章 DAO 模式
    JAVA / MySql 编程——第七章 JDBC
    JAVA / MySql 编程——第六章 Mysql 创建账户的相关命令
    JAVA / MySql 编程——第五章 事务、视图、索引、备份和恢复
    JAVA / MySql 编程—— 第四章 高级查询(二)
  • 原文地址:https://www.cnblogs.com/r360/p/4931661.html
Copyright © 2020-2023  润新知