block底层

本文详细介绍了Objective-C中的Block,包括Block的概念,它如何封装函数和调用环境,Block的分类(全局Block、栈Block、堆Block)。探讨了Block引发的循环引用问题及解决方案,如使用弱引用、中介者模式。此外,深入分析了Block的底层实现,包括Block的本质——匿名函数,获取外界变量的方式,Block的三次复制过程以及涉及到的关键函数如_Block_object_assign。通过这些内容,帮助读者理解Block的工作原理和内存管理。
摘要由CSDN通过智能技术生成

block概念

block本质上是一个OC对象(结构体),它享有所有OC对象的待遇,只不过普通OC对象用来封装数据,而block用来封装函数以及函数的调用环境。所谓封装函数,是指block内部会把block的参数、返回值、执行体封装成一个函数,并且存储该函数的内存地址;所谓封装函数的调用环境,是指block内部会捕获变量,并且存储这些捕获的变量。

block分类

  • NSGlobalBlock 全局block,位于内存全局区,未引用任何局部变量
void (^block)(void) = ^{
        NSLog(@"Cooci");
    };
    NSLog(@"%@",block);
  • NSMallocBlock,堆区 block , 引用局部变量的block,ARC下 将block赋值给strong引用时。打印的block就是 NSMallocBlock
int a = 10;
    void (^block)(void) = ^{
        NSLog(@"Cooci--%d",a);
    };
    NSLog(@"%@",block);
  • NSStackBlock,栈区BlockARC下 不将block赋值给 strong引用时。打印的block就是NSStackBlock
 int a = 10;
    void (^__weak block)(void) = ^{
        NSLog(@"Cooci - %d",a);
    };

    NSLog(@"%@",block);

##循环引用
循环引用.png
如图所示,A与B之间相互持有,导致两者之间都无法释放

NSString *name = @"Dragon";
self.block = ^(void){
    NSLog(@"%@",self.name);
};
self.block();

###解决方法

  • weak-stong-dance 强弱共舞
    • 如果block内部并未嵌套block,直接使用__weak修饰self即可
self.name = @"dragon";
    __weak typeof(self) weakSelf = self;
    self.block = ^(void){
        NSLog(@"%@",weakSelf.name);
    };
    self.block();
  • 如果block内部嵌套block,需要同时使用__weak__strong
self.name = @"cooci";
    __weak typeof(self) weakSelf = self;
    self.block = ^(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.block();
  • 中介者模式
    1. 手动释放
__block ViewController *vc = self;
self.block = ^(void){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@",vc.name);
        vc = nil;//手动释放
    });
};
self.block();

注:block必须调用,这样临时变量vc才能置空,以保证self与block的释放

2.自动释放

typedef void(^KCBlock)(ViewController *);

@property(nonatomic, copy) KCBlock block;

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

注:将对象self作为参数,提供给block内部使用,当self释放的时候对应的block也可以释放,就不会存在相互持有的问题

  • NSProxy虚拟类
    OC单继承机制,可以通过NSProxy实现伪多继承的方式
    NSProxy 和 NSObject是同级的一个类,也可以说是一个虚拟类,只是实现了NSObject的协议
    NSProxy 其实是一个消息重定向封装的一个抽象类,类似一个代理人,中间件,可以通过继承它
- (id)transformObjc:(NSObject *)objc{
   _objc = objc;
    return self;
}

+ (instancetype)proxyWithObjc:(id)objc{
    return  [[self alloc] transformObjc:objc];
}

//2.有了方法签名之后就会调用方法实现
- (void)forwardInvocation:(NSInvocation *)invocation
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值