block

# block 的底层实现

将main.m中的代码通过clang编译成main.cpp代码:

int main(int argc, const char * argv[]) {

    // insert code here...

    void (^blk)(void) = ^{ printf("FlyElephant---Block\n"); };

    blk();

    return 0;

}

block通过__main_block_impl_0初始化,后序工作通过 __block_impl ,__main_block_desc_0实现。

## __block_impl 

__block_impl结构体代码如下:

struct __block_impl {

  void *isa;

  int Flags;

  int Reserved;

  void *FuncPtr;

};

isa 指向实例对象,block 本身也是一个 Objective-C 对象。block 的三种类型:_NSConcreteStackBlock、_NSConcreteGlobalBlock、_NSConcreteMallocBlock,即当代码执行时,isa 有三种取值 :

impl.isa = &_NSConcreteStackBlock; 

impl.isa = &_NSConcreteMallocBlock; 

impl.isa = &_NSConcreteGlobalBlock;

Flags 按位承载 block 的附加信息;

Reserved 保留变量;

FuncPtr 函数指针,指向 Block 要执行的函数

以上的四个字段均在初始化的时候完成:

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {

   impl.isa = &_NSConcreteStackBlock;

   impl.Flags = flags;

   impl.FuncPtr = fp;

   Desc = desc;

 }


 其中FuncPtr指针指向的block函数:


 static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

  printf("FlyElephant---Block\n"); }



## __main_block_impl_0

struct __block_impl impl;

struct __main_block_desc_0* Desc;

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {

  impl.isa = &_NSConcreteStackBlock;

  impl.Flags = flags;

  impl.FuncPtr = fp;

  Desc = desc;

}

};

impl block 实现的结构体变量;

Desc 描述 block 的结构体变量;

__main_block_impl_0 结构体的构造函数,初始化结构体变量 impl、Desc;

## __main_block_desc_0 

static struct __main_block_desc_0 {

  size_t reserved;

  size_t Block_size;

} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

reserved 结构体信息保留字段

Block_size 结构体大小

整个实现过程就是初始化__main_block_impl_0,返回impl,执行impl->FuncPtr.

## block访问变量两种方式

1.静态变量,全局变量

block使用静态变量,全局变量,全局静态变量代码:

int global_val = 1;

static int static_global_val = 2;

int main(int argc, const char * argv[]) {

    // insert code here...

    static int static_val = 3;

    void(^blk)(void) = ^ {

        global_val = 2;

        static_global_val = 3;

        static_val = 4;

    };

    return 0;

}

对静态全局变量和全局变量访问和转换之前一样,对静态变量的方式是将指针保存了起来。block对于其自动变量而言没有将指针保存起来,是因为自动变量(局部变量)超出其作用域之后就会被废弃。

2.__block

通过__block看下代码:

__block int localValue = 0;

  void (^blk)(void) = ^{

      localValue = 1;

  };


  OC源码中的 __block localValue 翻译后变成了 __Block_byref_intValue_0 结构体指针变量 intValue,通过指针传递到 block 内,与静态变量的指针传递是一致的。

## block类型

block 有三种类型 NSConcreteGlobalBlock,NSConcreteStackBlock和NSConcreteMallocBlock。

## block 循环引用

如果在Block使用附有__strong修饰符的对象类型自动变量,那么当Block从栈复制到堆上时,该对象为Block所持有。

经典的循环引用是self与block之间的相互引用:

typedef void (^blk_t)(void);

@interface User()

{

    blk_t blk_;

}

@end

@implementation User

-(id)init

{

    self = [super init];

    blk_ = ^{NSLog(@"self = %@", self);};

    return self;

}

-(void)dealloc

{

    NSLog(@"dealloc");

}

@end

## __weak

__weak typeof(User) *weakself = self;

    blk_= ^{

        NSLog(@"FlyElephant--%ld", (long)weakself.age);

    };

    return self;

## __block避免循环引用:

typedef void (^blk_t)(void);

@interface User : NSObject

{

    blk_t blk_;

}

@end

@implementation User

-(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 main()

{

    id object = [[User alloc] init];

    [object execBlock];

    return 0;

}

该代码没有引起循环引用。但是如果不执行execBlock实例方式,即不执行复试给成员变量blk_的Block,会循环引用并引起内存泄漏。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 转载自:block没那么难(一):block的实现block没那么难(二):block和变量的内存管理block没...
    路漫漫其修远兮Wzt阅读 2,924评论 0 0
  • block写法: 普通写法: int (^blk)(int) = ^(int count) { retur...
    一川烟草i蓑衣阅读 2,649评论 0 0
  • Block概要 Block:带有自动变量的匿名函数。 匿名函数:没有函数名的函数,一对{}包裹的内容是匿名函数的作...
    zweic阅读 3,443评论 0 2
  • Block 前前后后看了4、5遍《Objective-C高级编程》的Block模块,对Block相关的内容有一定的...
    sycasl阅读 3,715评论 0 0
  • 前情提要 1.闭包、Block是一个带有自动变量值(可以截获自动变量值)的匿名函数。截获的含义是保存该自动变量的瞬...
    Jacob6666阅读 3,060评论 0 0

友情链接更多精彩内容