iOS Block原理及说明

1,339 阅读1分钟

Block类型

Block的三种类型:__NSGlobalBlock,__NSStackBlock,__NSMallocBlock

__NSGlobalBlock:没有引用变量或OC属性的block就是__NSGlobalBlock

__NSStackBlock:引用变量或OC属性的block就是__NSStackBlock

__NSMallocBlock:当一个__NSStackBlock调用了copy或强引用,返回的就是一个__NSMallocBlock

注:在ARC环境下,编译器会自动把栈上的block copy到堆上

拷贝block

如果原来就在堆上,就将引用计数加1

如果原来在栈上,会拷贝在堆上,引用计数初始化为1,并且会调用copy helper方法(如果存在的话)

如果block在全局区,不用加引用计数,也不用拷贝,直接返回block本身

参数arg就是block_layout对象

返回值是拷贝后的block的地址

触发拷贝时机

手动copy(MRC)

被强引用或copy修饰

系统API包含usingBlock

代码

#import "block.h"

@interface block ()

@property(nonatomic,copy)void(^block)(void);

@end

@implementation block

//编译过程
//clang
//老编译过程:语法检查->oc转换c/c++->生成中间码->llvm链接
//新编译过程:语法检查->生成中间码->llvm链接

-(void)done{
    //循环引用self->block->self
    //1.__weak没有引用修饰对象,把地址作为key把self作为value放在弱引用表中,当没有强引用的情况下释放为nil
    __weak typeof(self) weakSelf = self;
    
    //2.前提必须是__NSMallocBlock,__NSMallocBlock捕获了self,self被copy在堆上,再次强引用self,导致循环引用
    self.block = ^(){
        
        //3.weakSelf此时代表从弱引用表中取出的self
        NSLog(@"%@",weakSelf);
        
        //保活block,持续作用域为2秒
        __strong typeof(weakSelf) strongSelf = weakSelf;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
            NSLog(@"%@",strongSelf);
        });
    };
    
    self.block();
}

@end