美文网首页
iOS Block 解决循环引用

iOS Block 解决循环引用

作者: YourSummer | 来源:发表于2021-06-21 13:45 被阅读0次

首先解决循环引用

一. 基础控制器代码:

#import "ViewController.h"

/// 前两种解决循环引用
typedef void(^CPBlock)(void);
/// 用于第三种解决循环引用
typedef void(^CPParamBlock)(ViewController *);

@interface ViewController ()
/// 前两种解决循环引用示例
@property(nonatomic, copy) CPBlock block;
/// 用于第三种解决循环引用示例
@property(nonatomic, copy) CPParamBlock paramBlock;
@property(nonatomic, copy) NSString *name;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.name = @"CPBlock";
}
@end

二. Block循环引用示例代码

//1. self持有block
    self.block = ^(void){
        // block持有self
        NSLog(@"%@", self);
        // block持有self的属性name
        NSLog(@"%@", self.name);
    };
  1. 当self自身要释放的时候, 就需要先释放block,
  2. 要释放block, 就要先把执行体内部block对self的持有先释放,
  3. self的retainCount != 0, self.block的retainCount != 0, 两者永远不会被释放, 造成循环引用

三 敲重点 -- 解决循环应用

方法一. 弱引用方式解决循环应用代码 __weak

-(void)resolveRetainCycle_1{
    __weak typeof(self) weakSelf = self;
    self.block = ^(void){
        NSLog(@"%@", weakSelf);
        // 如果block执行体内有耗时操作, 或者异步操作, 那么我们还需要优化循环引用的解决方案
        // strongSelf为block执行体内局部变量, 在block执行体范围内使用, 当block被释放, strongSelf也会被自动释放
        __strong typeof(weakSelf)strongSelf = weakSelf;
        // 以此异步延迟2秒任务模拟耗时操作
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@", strongSelf.name);
        });
    };
    self.block();
}

方法二. 截获变量方式 __block

-(void)resolveRetainCycle_2{
    // 截获当前ViewController
    // 需要手动释放 vc = nil;
    __block ViewController *vc = self;
    self.block = ^(void){
        // 以此异步延迟2秒任务模拟耗时操作
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@", vc.name);
            vc = nil;
        });
    };
    self.block();
}

方法三. 通讯传值方式

/// 解决循环引用方法三
-(void)resolveRetainCycle_3{
    // 把self(实际为当前控制器: ViewController)作为一个临时变量传进block执行体
    // 不会造成循环引用
    self.paramBlock = ^(ViewController *vc){
        // 以此异步延迟2秒任务模拟耗时操作
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@", vc.name);
        });
    };
    self.paramBlock(self);
}

相关文章

网友评论

      本文标题:iOS Block 解决循环引用

      本文链接:https://www.haomeiwen.com/subject/ngfyyltx.html