OC 的 Block 简析1 - 三种类型

本文主要介绍 Block 的三种类型。

OC底层探索26、Block 原理

一、Block 是什么?

在 OC 文档的 Working with Blocks 中:

  Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary.

Block 官方文档: Block Programming Topics 中:

  As an optimization, block storage starts out on the stack—just like blocks themselves do.

block 是一个 OC 对象,但是它和普通的O从对象又不一样。

block 默认在 栈上分内存,而我们一般的对象是在堆上。

二、block 有三种类型: 全局 / 栈 / 堆  block

1、全局block -  __NSGlobalBlock__

- (void)block3 {
    // 声明: typedef  NSString *(^MyBlock)(NSString *str);
    MyBlock block = ^(NSString *str){
        
        NSLog(@"处理一些无关于外部属性的事务");
        return str;
    };
    block(@"");
    NSLog(@"block类型%@",block);
}

2、栈block -  __NSStackBlock__

- (void)block2 {
    
    int a = 1;
    
    NSLog(@"block类型%@",^{ NSLog(@"block 0:%i", a); });
}

3、堆block -  __NSMallocBlock__

- (void)block1 {
    void (^blockObject)(void);
    blockObject = ^{ NSLog(@"block 0:%i", a); };
    blockObject();
    
    NSLog(@"block类型%@",blockObject);
}

从上面3部分代码中,我们可看出三者区别:

全局block:block 没有访问任何外部变量的;

栈block: block 访问了外部对象,但没有copy操作;

堆block:相对于栈block来说:我们声明定义了一个block同时访问了外部变量则(不访问就是全局)(不声明定义就是栈),此过程本质就是栈-变->堆的过程,系统帮我们做了copy,栈的block迁移到了堆里。

4、关于堆block 详解

代码示例:

- (void)block1 {
    
    /* __block 允许block内部使用,
    */
    __block NSString *blockStr = @"局部str";
    MyBlock block = ^(NSString *str){
        
        /*
         block 内部操作:将对象 copy 了一个新的到堆上,指针不变,但指针指向新的对象
        */
        self->globalStr = @"block内修改全局";
         blockStr = str;

        NSLog(@"内globalStr== %@ %p %p",self->globalStr,self->globalStr,&self->globalStr);

        [self logstr:blockStr];
        
        return str;
    };
    
    NSLog(@"block类型%@",block);
    NSLog(@"外globalStr== %@ %p %p",globalStr,globalStr,&globalStr);
    NSLog(@"外blockStr== %@ %p %p",blockStr,blockStr,&blockStr);

    block(@"执行block,改局部str");
}
- (void)logstr:(NSString *)blockStr {
    
    NSLog(@"globalStr2== %@ %p %p",globalStr,globalStr,&globalStr);

    /*
     局部str,拿到外部,创建了一个新的指向它的指针
    */
    NSLog(@"blockStr2== %@ %p %p",blockStr,blockStr,&blockStr);
}

运行结果如图:

 

我们可以看到,不论是函数中的局部变量 还是当前文件范围的局部变量(注意:代码里的‘全局’并非是真正的全局,只是为了用来区分函数内部变量), 在 block 内部进行使用,对象都不是外部的那个对象了,但是指向对象的指针不变 --> 即:指针指向的对象是一个copy出来的新的。如下图:

 

从而,也可知,block内部会对我们的对象进行copy,但是指向对象的指针不变,指针指向对象会变成新的。 

而函数内部的局部变量被拿出去函数外部使用时,相当于 创建了一个新 的指向这个改变后对象的 指针。

 

待续... ...

以上。 

 

posted @ 2020-09-15 00:31  张张_z  阅读(1225)  评论(0编辑  收藏  举报