iOS Block 原理

目前常用的几种设计模式有:代理模式、KVC模式、KVO模式、Block模式等
这么多设计模式中 , 如果问哪一种使用的最多 , 被提及的最多 . Block 一定是你脑海中第一想到的吧.
参考了一些资料 下面我就同大家一起分享下,我对block的一些了解.

Block 底层原理


  • block底层就是一个struct __main_block_impl_0类型的结构体,这个结构体中包含一个
    isa指针,本质上是一个OC对象 block是封装了函数调用以及函数调用环境的OC对象,
    block底层结构 block底层结构就是__main_block_impl_0结构体,内部包含了impl结构体和Desc结构体以及外部需要访问的变量,block将需要执行的代码放到一个函数里,impl内部的FuncPtr指向这个函数的地址,通过地址调用这个函数,就可以执行block里面的代码了。Desc用来描述block,内部的reserved作保留,Block_size描述block占用内存

Block 的内存管理


  • 无论当前环境是ARC还是MRC , 只要block没有访问外部变量 , block始终在全局区

  • MRC情况下:

    ◦ block如果访问了外部变量,block在栈里
    ◦ 不能对block使用retain , 否则不能保存在堆里
    ◦ 只有使用copy , 才能存放在堆里

  • ARC情况下:

    ◦ block如果访问了外部变量,block在堆里
    ◦ block使用copy和strong , block是一个对象

Block 使用中需注意以下几点


  • 如果直接在block内使用外部强指针会发生内存泄露 , 以下代码在block外部实现可以解决强引用造成的此类问题.

       __weak typeof(self) weakSelf = self; 
    
  • 但在block内部使用延时操作还使用弱指针的话就有可能取不到该弱指针 , 此时需要在block内部再将弱指针强引用一下.

       __strong typeof(self) strongSelf = weakSelf;  
    
  • 如果在block内部对外部(局部)变量修改的话 , 需要在变量前使用__block修饰外部变量 , 否则会提示错误

        void test(){        
             // int 为局部变量 添加了修饰符__block后可对变量进行修改
             __block int a = 10;
             void (^block)() = ^{
                  a = 20;
                  NSLog(@"a is %d", a);
             };
             block() ; //输出结果为 20
        }
    
  • 如果block访问的变量是局部变量 , 那么进行的就是传值操作 , 外部变量改变不会影响block内部数值 . 当局部变量添加 _block 修饰符后,对变量的访问就变成了传址操作 ,外部变量的改变内部也会跟着改变.

       // int 为局部变量此时是(传值)操作                         //添加了修饰符_block后此时是(传址)操作
       void test(){                                             void test(){
             int a = 10;                                            __block  int a = 10;
             void (^block)() = ^{                                   void (^block)() = ^{
    
                 NSLog(@"a is %d", a);                                       NSLog(@"a is %d", a);
             };                                                      };
             a = 20;                                                 a = 20;
             block(); 打印结果: 10                                    block(); 打印结果: 20  
                          
         }                                                       }
    
  • 当block访问的是 static 修饰符的局部变量 或者 访问的是全局变量的话 , 那么就是进行的传址操作 , block里面和外部同一个变量,外面改变,里面也跟着改变.

         // static 修饰的局部变量为(传址)操作                        //类的成员变量进行的是(传址)操作
         void test() {                                             self.a = 10;
               static int a = 10;                                  void test() {
               void (^block)() = ^{                                     void (^block)() = ^{
                                 
                  NSLog(@"a is %d", a);                                    NSLog(@"a is %d", a);
               };                                                      };
               a = 20;                                                self. a = 20;
               block(); 打印结果: 20                                    block(); 打印结果: 20
    
          }                                                        }
    

Block 优点


  • block使用使代码块更加紧凑.

  • 不再需要去遵守过多的协议,使用更加简洁.

文章持续更新中、希望对各位有所帮助、有问题可留言 大家共同学习.

你可能感兴趣的:(iOS Block 原理)