OC Block bottom layer

type of block

1.__NSGlobalBlock__

block has no parameters and no return value

void(^block)(void) = ^{
        NSLog(@"aaaaaaa");
    };
    NSLog(@"%@", block);
aaa[6077:155418] <__NSGlobalBlock__: 0x10d32e0e0>

2.__NSMallocBlock__

block accesses external variables

int a = 100;
    void(^block)(void) = ^{
        NSLog(@"aaaaa - %d", a);
    };
    NSLog(@"%@", block);
aaa[6346:163587] <__NSMallocBlock__: 0x6000013a9a10>

3.__NSStackBlock__ 

Block accesses external variables while using weak weak references

int a = 100;
    void(^__weak block)(void) = ^{
        NSLog(@"aaaaa - %d", a);
    };
    NSLog(@"%@", block);
aaa[6485:167690] <__NSStackBlock__: 0x7ff7b7e3bae8>

Summarize

  • If the block does not access external variables , it is directly stored in the global area
  • Block accesses external variables , strong references, stored in the heap area
  • Block accesses external variables , weak references, stored in the stack area

 

circular reference

//代码一
    NSString *name = @"AAA";
    self.block = ^(void){
        NSLog(@"%@",self.name);
    };
    self.block();

    //代码二
    UIView animateWithDuration:1 animations:^{
        NSLog(@"%@",self.name);
    };

In code 1, because self holds the block, and the block accesses self.name, the block also holds self, so self and block hold each other , so a circular reference occurs in code 1. Code Two does not constitute mutual holding. Here are a few ways to resolve circular references:

1.weak-stong-dance

__weak typeof(self) weakSelf = self;
self.slBlock = ^(void){
    __strong typeof(weakSelf) strongSelf = weakSelf;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",strongSelf.name);
    });
};
self.slBlock();

__weak modifies self to break self's strong reference to block. If block is nested inside block, you need to use __weak and __strong at the same time

2. __block modifier variables

__block ViewController *vc = self;
self.slBlock = ^(void){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",vc.name);
        vc = nil;//手动释放
    });
};
self.sllBlock();

The block must be called , otherwise there will still be a circular reference

3. self as a block parameter


self.slBlock = ^(ViewController *vc){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",vc.name);
    });
};
self.slBlock(self);

4. NSProxy virtual class

NSProxy can realize pseudo-multi-inheritance . Referring to YYWeak of YYkit, NSProxy solves the problem NSTimer和CADisplayLinkof creation 对self强引用. NSProx is like an agent, which can realize message forwarding by inheriting it and rewriting the two methods (forwardInvocation, methodSignatureForSelector) for slow forwarding of messages

Customize a NSProxy

@interface SLProxy : NSProxy
- (id)transformObjc:(NSObject *)objc;
+ (instancetype)proxyWithObjc:(id)objc;
@end

@interface SLProxy()
@property(nonatomic, weak, readonly) NSObject *objc;
@end

@implementation SLProxy
- (id)transformObjc:(NSObject *)objc{
   _objc = objc;
    return self;
}
+ (instancetype)proxyWithObjc:(id)objc{
    return  [[self alloc] transformObjc:objc];
}
- (BOOL)respondsToSelector:(SEL)aSelector{
    return [self.objc respondsToSelector:aSelector];
}
//1、查询该方法的方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    NSMethodSignature *signature;
    if (self.objc) {
        signature = [self.objc methodSignatureForSelector:sel];
    }else{
        signature = [super methodSignatureForSelector:sel];
    }
    return signature;
}
//2.有了方法签名之后就会调用方法实现
- (void)forwardInvocation:(NSInvocation *)invocation{
    SEL sel = [invocation selector];
    if ([self.objc respondsToSelector:sel]) {
        [invocation invokeWithTarget:self.objc];
    }
}

Customize Cat and Bird classes

#import "ViewController.h"
#import "SLProxy.h"

//********Cat类********
@interface Cat : NSObject
@end
@implementation Cat
- (void)eat{
   NSLog(@"我爱吃鱼");
}
@end

//********Bird类********
@interface Bird : NSObject
@end

@implementation Bird
- (void)fly{
    NSLog(@"我会飞");
}
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self cjl_proxyTest];
}

- (void)cjl_proxyTest{
    Bird *bird = [[Bird alloc] init];
    Cat *cat = [[Cat alloc] init];
    SLProxy *proxy = [SLProxy alloc];
    
    [proxy transformObjc:cat];
    [proxy performSelector:@selector(eat)];
    
    [proxy transformObjc:bird];
    [proxy performSelector:@selector(fly)];
}


@end

SLProxy loves to eat fish and can also fly, possessing the abilities of cats and birds

Solve the strong reference of timer self through NSProxy

self.timer = [NSTimer timerWithTimeInterval:1 target:[SLProxy proxyWithObjc:self] selector:@selector(print) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];

Block bottom layer

define a block

- (void)viewDidLoad {
    [super viewDidLoad];

    void(^block)(void) = ^{
        printf("aaaaa");
    };
}

After compiling into cpp, the result is as follows

struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl;
  struct __ViewController__viewDidLoad_block_desc_0* Desc;
  __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself) {

        printf("aaaaa");
    }

static struct __ViewController__viewDidLoad_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __ViewController__viewDidLoad_block_desc_0_DATA = { 0, sizeof(struct __ViewController__viewDidLoad_block_impl_0)};

static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));
    void(*block)(void) = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA));
}
// @end

Equivalent to blockequals __ViewController__viewDidLoad_block_impl_0, is a function.

Checking __ViewController__viewDidLoad_block_impl_0定义,是一个结构体,can also show that block is a __ViewController__viewDidLoad_block_impl_0type of object, which is why it blockcan be %@printed. blockThe thing 本质is 对象、函数、结构体, since the block function has no name, it is also called匿名函数。

1.block是需要调用的

Function declaration: the internal implementation of the block is declared as a function __ViewController__viewDidLoad_block_func_0​​​​​​​

Execute specific function implementation:FuncPtr call the block to execute by calling the pointer of the block

2.block捕获外界变量

- (void)viewDidLoad {
    [super viewDidLoad];

    int t = 10;
    void(^block)(void) = ^{
        printf("aaaaa - %d",t);
    };
    
    block();
}

compile to cpp

struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl;
  struct __ViewController__viewDidLoad_block_desc_0* Desc;
  int t;
  __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, int _t, int flags=0) : t(_t) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself) {
  int t = __cself->t; // bound by copy

        printf("aaaaa - %d",t);
    }

static struct __ViewController__viewDidLoad_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __ViewController__viewDidLoad_block_desc_0_DATA = { 0, sizeof(struct __ViewController__viewDidLoad_block_impl_0)};

static void _I_ViewController_viewDidLoad(ViewController * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));
    int t = 10;
    void(*block)(void) = ((void (*)())&__ViewController__viewDidLoad_block_impl_0((void *)__ViewController__viewDidLoad_block_func_0, &__ViewController__viewDidLoad_block_desc_0_DATA, t));
    ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}

It can be seen that when the block captures external variables, it will be in内部会自动生成同一个属性来保存

如果外界变量t用__block修饰,然后在block中对t进行修改,编译如下

struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl;
  struct __ViewController__viewDidLoad_block_desc_0* Desc;
  __Block_byref_t_0 *t; // by ref
  __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, __Block_byref_t_0 *_t, int flags=0) : t(_t->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __ViewController__viewDidLoad_block_func_0(struct __ViewController__viewDidLoad_block_impl_0 *__cself) {
  __Block_byref_t_0 *t = __cself->t; // bound by ref

        (t->__forwarding->t)++;
        printf("aaaaa - %d",(t->__forwarding->t));
    }
。。。
// @end

​​​​​​​​The structure  will外界变量 be generated to save the original variable pointer and value, and the external variable can be operated inside the block (that is, pointer copy ).__Block_byref_a_0

The bottom real type of Block

Looking at the libclosure source code, we can see that the real type of the block is a structure .

// CJL注释:Block 结构体
struct Block_layout {
    //指向表明block类型的类
    void *isa;//8字节
    //用来作标识符的,类似于isa中的位域,按bit位表示一些block的附加信息
    volatile int32_t flags; // contains ref count 4字节
    //保留信息,可以理解预留位置,用于存储block内部变量信息
    int32_t reserved;//4字节
    //函数指针,指向具体的block实现的调用地址
    BlockInvokeFunction invoke;
    //block的附加信息
    struct Block_descriptor_1 *descriptor;
    // imported variables
};

Guess you like

Origin blog.csdn.net/weixin_38016552/article/details/129197859