iOS与OS X多线程和内存管理(二)Blocks

2018-08-22  本文已影响28人  丁宝2012

前言

上篇文章整理了关于“内存管理”的知识点,这篇主要整理“Blocks”的内容,在学习Blocks的内容时,我一开始也采取了学习“内存管理”时采用的先阅读《iOS与OS X多线程和内存管理》再配合《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法 》,但是在学习《iOS与OS X多线程和内存管理》时有些理解比较困难,恰恰《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法 》中的内容虽然比较少,但对阅读《iOS与OS X多线程和内存管理》中的内容很有帮助,当然还有别的学习途径。以下内容如有理解错误的地方,希望大家指出,我们一起学习和探讨~

什么是blocks

BIocks是C语言的扩充功能,可概括为:带有自变量值的(局部变量)的匿名函数(匿名函数就是不带名称的函数)

Blocks模式

Block语法(Block表达式语法)

3B1C4EF3D014B48AC387BB30F4EF3B19.png
   ^int (int count){return count + 1;}
//表达式中含有return语句时,其类型必须与返回值类型相同
EBD14914984DE1B285DDDC1D77552435.png
   ^ (int count){return count + 1;}
//省略返回值类型时,如果表达式中有return语句就使用该返回值的类型,如果表达式中没有return语句就是void类型,表达式中含有多个return语句时,所以return的返回值类型必须相同
71CC51D2A6B5806002181794275456AE.png
//不使用参数的Block语法
 ^void (void){ }
//省略后表达式为
 ^{ }

Block类型变量

  int (^blk)(int);
返回类型(^变量名)(参数)
  //-使用Block语法将Block赋值为Block类型变量
  int(^blk)(int) = ^int(int count){return count + 1;};

  //由Block类型变量向Block类型变量赋值
  int(^blk1)(int) = blk;
  
  int(^blk2)(int);
  blk2 = blk1;

  //在函数参数中使用Block类型变量可以函数传递Block(值)
  void fun(int(^blk)(int)){
    
  }

  //在函数返回值中指定Block类型,可以将Block作为函数的返回值返回
   int(^func())int{
        return ^(int count){return count + 1;};
    }

  //使用  typedef 
  typedef int(^blk_t) int;
  //原记述方式
  void fun(int(^blk)(int)){
  }
  //等价于
  void fun(int(blk_t blk){
  }

  //原记述方式
    int(^func())int{
        return ^(int count){return count + 1;};
    }
  //等价于
  blk_t func{
  }

截获自动变量值

  int main{
    int day = 256;
    int val = 10;
    const char *fmt = "val = %d\n";
    void (^ blk)(void) = ^{
        printf(fit , val);
     };
    
    val = 2;
    fmt = "There values were changed . val = %d\n";
    blk();
    return 0;
  }

  /*
    *Block语法的表达式使用的是它之前声明的自动变量fmt和val
    *Blokcs中,Block表达式中截获所使用的自动变量的值,即Block表达式保存该自动变量的瞬间值
    *执行Block语法后,即使改写Block中使用的自动变量也不会影响Block执行时自定变量的值
    *结果输出 val = 10;
    */

_ _block说明符

  int val = 0;
  void (^blk)(void) = ^{ val = 1;};
  blk();
  printf("val = %d\n");

  //编译报错
  _ _block int val = 0;
  void (^blk)(void) = ^{ val = 1;};
  blk();
  printf("val = %d\n");

  //结果输出:val = 1;

截获自动变量

   id array = [[NSMutableArray alloc] init];
   void (^blk) (void) = ^{
        id obj = [[NSObject alloc] init];
        [arrray addObject:obj];
    }
    /*
     *编译不会报错
     *代码中截获的是变量值为NSMutableArray类的对象(即截获的是NSMutableArray类对象用的结构体实例指针)
     *截获OC对象,调用变更改对象的方法(addObject),即使用截获对象不会出现任何错误
     */

   id array = [[NSMutableArray alloc] init];
   void (^blk) (void) = ^{
        array = [[NSMutableArray alloc] init];
    }
    /*
     *编译报错
     *向截获的变量array赋值会产生编译错误
     */

    _ _block id array = [[NSMutableArray alloc] init];
   void (^blk) (void) = ^{
        array = [[NSMutableArray alloc] init];
    }
    //编译成功

Blocks实现

Block的实质

Block存储域

1E0C18A7-FB73-4E72-95D8-5C30B2AD01DA.png C9F96C19-10DF-4D5B-99BC-EA3B465B377D.png 2C9642D6-9F9B-439F-8D37-D88C197E1787.png 01674628-B6AD-4843-888A-23DDC7D2E66B.png

_ _block变量存储域

image 66FC9034-763C-412F-AE51-070DFA21666E.png BF70ABC0-60DC-4C31-9550-41EB64317008.png

截获对象

    id array = [[NSMutableArray alloc] init];
    blk_t blk;
    {
        id array = [[NSMutableArray alloc] init];
        blk = [^(id obj){
            [array addObjct:obj];
            NSLog(@"array count = %ld",[array coun]);
      } copy];
    }
    blk ([[NSObject alloc] init]);
    blk ([[NSObject alloc] init]);
    blk ([[NSObject alloc] init]);

    //输出结果
    array count = 1
    array count = 2
    array count = 3

   /*
    *输出结果意味着,赋值给变量array的NSMutableArray类的对象在该源代码最后Block的执行部分超出变量作用域而存在
    *被赋值NSMutableArray类对象并被截获的自动变量array,它是Block用的结构体中附有_strong修饰符的成员变量
    struct _main_block_impl_0{
      struct _block_impl impl;
      struct _main_block_desc_0 *Desc;
      id strong array;
    }
    *Block用结构体中,还有附有_strong修饰符的对象类型变量array,所以需要恰当管理赋值给变量array的对象,因此_main_block_copy_0函数使用_Block_object_assjgn函数将对象类型对象赋值给Block用结构体的成员变量array中并持有该对象
    *_Block_object_assjgn函数调用相当一retain实例方法函数,将对象赋值给对象类型的结构体成员变量中
    *_main_block_dispose_0函数使用_Block_object_dispose函数,释放赋值在Block用结构体成员变量array中的对象,相当于release实例方法,释放赋值在对象类型结构体成员变量中的对象
    */
4203D13C-5B6B-4073-8AD2-942AB2D2A890.png 4888C201-5B2E-4BB5-A492-8463000A0CA7.png

_ _block变量和对象

    blk_t blk;
    {
        id array = [[NSMutableArray alloc] init];
        id _ _weak array2 = array;
        _ _block id _ _weak array3 = array;
        blk = [^(id obj){
            [array2 addObjct:obj];
            NSLog(@"array2 count = %ld,array2 count = %ld",[array2 coun],[array3 coun]);
      } copy];
    }
    blk ([[NSObject alloc] init]);
    blk ([[NSObject alloc] init]);
    blk ([[NSObject alloc] init]);

    //输出结果
    array2 count = 0 array3 count = 0
    array2 count = 0 array3 count = 0
    array2 count = 0 array3 count = 0


   /*
    *由于附有_strong修饰符的变量array在该变量作用域结束的同时释放、废弃,nil被赋值在附有_ _weak修饰符的变量array2中,即使附加 _ _block修饰符附有_strong修饰符的变量array在该变量作用域结束的同时释放、废弃,nil被赋值在附有_ _weak修饰符的变量array3中
    */

Block循环引用

typedef void (^blk_t) (void);

@interface MyObject : NSObject
{
    blk_t blk_;
}
@end


@implementation MyObject

-(id)init{
    self = [super init];
    blk_ = ^{ NSLog(@"self = %@", self); }
    return self;
}

-(void)dealloc{
    NSLog(@"dealloc");
}

@end

int mian(){
    id o = [[MyObject alloc] init];
    NSLog(@"%@", o );
    return o;
}

/*
 * MyObject类的dealloc实例方法一定没有被调用
 * MyObject类对象的Block类型成员变量blk_持有赋值为Block的强引用(MyObject类对象持有Block)
 *init实例方法中执行的Block语法使用附有_strong修饰符的id类型变量self
 *由于Block语法赋值在成员变量blk_中,通过Block语法生成在栈上的Block此时有栈复制在堆上,并持有所使用的self,self持有Block,Block持有self,形成循环引用
 */
D7124496FF78DECEAC96909FD5C49DCF.jpg
-(id)init{
    self = [super init];
    id _ _weak tmp = self;
    blk_ = ^{ NSLog(@"self = %@", tmp); }
    return self;
}
F2598D7757C5843EE46FC8CFA534C296.jpg
typedef void (^blk_t) (void);

@interface MyObject : NSObject
{
    blk_t blk_;
}
@end


@implementation MyObject

-(id)init{
    self = [super init];
    _ _block id tmp = self;
    blk_ = ^{
         NSLog(@"self = %@", tmp);
         tmp = nil;
    }
    return self;
}

-(void)execBlock{
  blk_();
}
-(void)dealloc{
    NSLog(@"dealloc");
}

@end

int mian(){
    id o = [[MyObject alloc] init];
    [o execBlock];
    return o;
}

2A6F5F4B537D7C2B4272E34F0E73A605.jpg
    blk_ = ^{
         NSLog(@"self = %@", tmp);
         tmp = nil;
    }
 /*
  *_ _block 变量tmp对MyObject类对象的强引用失效,避免循环引用
  * MyObject类对象持有Block
  * Block持有 _ _block 变量
  */ 

AF9D11E4CFFC05E678884E0135F637DC.jpg

copy/release

上一篇下一篇

猜你喜欢

热点阅读