iOS性能优化-Block

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a184251289/article/details/82591338

一、循环引用

原因是使用MRC管理内存时,Block的内存管理需要区分是Global(全局)、Stack(栈)还是Heap(堆),而在使用了ARC之后,苹果自动会将所有原本应该放在栈中的Block全部放到堆中。全局的Block比较简单,凡是没有引用到Block作用域外面的参数的Block都会放到全局内存块中,在全局内存块的Block不用考虑内存管理问题。(放在全局内存块是为了在之后再次调用该Block时能快速反应,当然没有调用外部参数的Block根本不会出现内存管理问题)。

所以Block的内存管理出现问题的,绝大部分都是在堆内存中的Block出现了问题。默认情况下,Block初始化都是在栈上的,但可能随时被收回,通过将Block类型声明为copy类型,这样对Block赋值的时候,会进行copy操作,copy到堆上,如果里面有对self的引用,则会有一个强引用的指针指向self,就会发生循环引用,如果采用weakSelf,内部不会有强类型的指针,所以可以解决循环引用问题。

那是不是所有的block都会发生循环引用呢?其实不然,比如UIView的类方法Block动画,NSArray等的类的遍历方法,也都不会发生循环引用,因为当前控制器一般不会强引用一个类。


二、解决方案

参照libextobjc中的weakify和strongify。

    @weakify(self)
    [self.LoadView setRetryBlock:^{
        @strongify(self)
        [self.foo load:self.data];
    }];

三、经典案例

代码片段ModelOne.h

#import <Foundation/Foundation.h>
typedef void (^ModelOneBlock) (void);

@interface ModelOne : NSObject
- (void)cycle:(ModelOneBlock)block;
- (void)compare:(ModelOneBlock)block;
@end

代码片段ModelOne.m

#import "ModelOne.h"

@interface ModelOne ()
@property (nonatomic, copy) ModelOneBlock block;
@end

@implementation ModelOne
- (void)cycle:(ModelOneBlock)block{
    _block = block;
    if (_block){
        _block();
    }
}

- (void)compare:(ModelOneBlock)block{
    if (block){
        block();
    }
}
@end

循环引用CycleOneViewController

#import "CycleOneViewController.h"
#import "ModelOne.h"
@interface CycleOneViewController ()

@property (nonatomic, strong)ModelOne *model;

@end

@implementation CycleOneViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.model cycle:^{
        self.view.backgroundColor = [UIColor yellowColor];
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)dealloc{
    NSLog(@"dealloc");
}

- (ModelOne *)model{
    if(!_model){
        _model = [ModelOne new];
    }
    return _model;
}

对比CompareOneViewController

#import "CompareOneViewController.h"
#import "ModelOne.h"
#import "BlockConstants.h"

@interface CompareOneViewController ()

@property (nonatomic, strong)ModelOne *model;

@end

@implementation CompareOneViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.model compare:^{
        self.view.backgroundColor = [UIColor yellowColor];
    }];

    @weakify(self);
    [self.model cycle:^{
        @strongify(self);
        self.view.backgroundColor = [UIColor yellowColor];
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)dealloc{
    NSLog(@"dealloc");
}

- (ModelOne *)model{
    if(!_model){
        _model = [ModelOne new];
    }
    return _model;
}

CycleOneViewController是一个比较典型的循环引用。CompareOneViewController是没有循环引用的。Demo地址


四、解析

1、首先观察一下类ModelOne的两个方法。
- (void)cycle:(ModelOneBlock)block会持有block,给成环提供了必要条件。

- (void)compare:(ModelOneBlock)block不会持有block,该方法没有循环引用的风险。

2、外部斩断环
类CompareOneViewController在调用cycle方法时,用weakself替换了self,将强引用strong变成了弱引用weak。从外部斩断了成环的可能性。

    @weakify(self);
    [self.model cycle:^{
        @strongify(self);
        self.view.backgroundColor = [UIColor yellowColor];
    }];

Tips:使用weakify和strongify时注意,block内部不能使用下划线方式,会产生循环引用。

    @weakify(self);
    [self.model cycle:^{
        @strongify(self);
        _dataView.backgroundColor = [UIColor yellowColor];
        //self.dataView.backgroundColor = [UIColor yellowColor];
    }];

五、检测

Xcode->build setting->implicit retain of ‘self’ within blocks


摘要

https://juejin.im/post/58ca0832a22b9d006418fe43
https://github.com/jspahrsummers/libextobjc

猜你喜欢

转载自blog.csdn.net/a184251289/article/details/82591338