iOS 开发 Objective-C

iOS 底层 day08 block 底层结构 变量捕获 类型

2020-08-30  本文已影响0人  望穿秋水小作坊

一、block 引用外部变量时,对外部变量的捕获(capture)情况

1. 引用全局变量block,能简单说下ta的底层结构吗?
#import <Foundation/Foundation.h>
static int age = 10;
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        void (^lspBlock)(void) = ^{
            NSLog(@"我是简单的block:%d",age);
        };
        lspBlock();
    }
    return 0;
}
block中引用了全局变量
2. 引用局部变量的block,能简单说下ta的底层结构吗?
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        static int age = 10;
        void (^lspBlock)(void) = ^{
            NSLog(@"我是简单的block:%d",age);
        };
        lspBlock();
    }
    return 0;
}

引用局部变量的block
3. 引用局部变量的block,能简单说下ta的底层结构吗?
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 10;
        void (^lspBlock)(void) = ^{
            NSLog(@"我是简单的block:%d",age);
        };
        lspBlock();
    }
    return 0;
}
引用局部变量的block
4. 接下来我们总结一下 block引用外部变量,在各种情况下的捕获情况
捕获机制总结-牢记
5. 明白了 block 捕获原理后,我们来强化一下,请问下面代码的输出是多少?
#import <Foundation/Foundation.h>
int globalAge = 10;
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 20;
        static int staticAge = 30;
        void (^lspBlock1)(void) = ^{
            NSLog(@"我是简单的block:%d",globalAge);
        };
        void (^lspBlock2)(void) = ^{
            NSLog(@"我是简单的block:%d",age);
        };
        void (^lspBlock3)(void) = ^{
            NSLog(@"我是简单的block:%d",staticAge);
        };
        
        globalAge++;
        age++;
        staticAge++;
        
        lspBlock1();
        lspBlock2();
        lspBlock3();
    }
    return 0;
}
Demo[6041:138667] 我是简单的block:11
Demo[6041:138667] 我是简单的block:20
Demo[6041:138667] 我是简单的block:31
6.请问下面的 block 有捕获变量吗?捕获的是谁?
#import "Person.h"
@interface Person ()
@property(nonatomic, assign) int age;
@end

@implementation Person
- (void)lspTest {
    void (^block)(void) = ^{
        NSLog(@"%i", _age);
    };
    block();
}
@end
static void _I_Person_lspTest(Person * self, SEL _cmd) {
    void (*block)(void) = ((void (*)())&__Person__lspTest_block_impl_0((void *)__Person__lspTest_block_func_0, &__Person__lspTest_block_desc_0_DATA, self, 570425344));
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}

二、block 的类型

1. 除了 block 有 isa 指针这个方面来说,我们还可以从哪方面证明 block 是一个 OC 对象?
#import <Foundation/Foundation.h>
int globalAge = 10;
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int age = 20;
        static int staticAge = 30;
        void (^lspBlock1)(void) = ^{
            NSLog(@"我是简单的block:%d",globalAge);
        };
        void (^lspBlock2)(void) = ^{
            NSLog(@"我是简单的block:%d",age);
        };
        void (^lspBlock3)(void) = ^{
            NSLog(@"我是简单的block:%d",staticAge);
        };
        
        void (^lspBlock4)(void) = [lspBlock2 copy];
        
        NSLog(@"lspBlock1: %@, %@, %@, %@",[lspBlock1 class],
              [lspBlock1 superclass],
              [[lspBlock1 superclass] superclass],
              [[[lspBlock1 superclass] superclass] superclass]);
        
        
        NSLog(@"lspBlock2: %@, %@, %@, %@",[lspBlock2 class],
              [lspBlock2 superclass],
              [[lspBlock2 superclass] superclass],
              [[[lspBlock2 superclass] superclass] superclass]);
        
        
        NSLog(@"lspBlock3: %@, %@, %@, %@",[lspBlock3 class],
              [lspBlock3 superclass],
              [[lspBlock3 superclass] superclass],
              [[[lspBlock3 superclass] superclass] superclass]);
        
        NSLog(@"lspBlock4: %@, %@, %@, %@",[lspBlock4 class],
              [lspBlock4 superclass],
              [[lspBlock4 superclass] superclass],
              [[[lspBlock4 superclass] superclass] superclass]);
        
    }
    return 0;
}

Demo[6201:154701] lspBlock1: __NSGlobalBlock__, __NSGlobalBlock, NSBlock, NSObject
Demo[6201:154701] lspBlock2: __NSStackBlock__, __NSStackBlock, NSBlock, NSObject
Demo[6201:154701] lspBlock3: __NSGlobalBlock__, __NSGlobalBlock, NSBlock, NSObject
Demo[6201:154701] lspBlock4: __NSMallocBlock__, __NSMallocBlock, NSBlock, NSObject
2. 既然 block 有三种类型,你能从它们的名字,区分出运行时,它们分别放在内存的哪一段吗?
3. 既然 block 有三种类型,那对它们进行 copy 操作会有什么效果呢?
copy 操作-牢记
4. 你可能会遇到的疑惑,如果将 1 中的代码,转换成 c++ 代码
struct __main_block_impl_1 {
  struct __block_impl impl;
  struct __main_block_desc_1* Desc;
  int age;
  __main_block_impl_1(void *fp, struct __main_block_desc_1 *desc, int _age, int flags=0) : age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
上一篇下一篇

猜你喜欢

热点阅读