不要濫用懶加載

寫代碼是一種習慣的養成,一種生活的態度。ios

有一次同事看着我寫的代碼說,你爲何要這麼寫啊?編程

我看了一下,原來是在 ViewController 和 Cell 裏初始化視圖,還有數據模型數組的時候,我都是用的懶加載(Lazy-Load)。數組

是啊,我爲何這麼喜歡用懶加載來實例化一個屬性呢?網絡

之前學 iOS 開發的時候,ide

  1. 以爲懶加載能夠延遲加載,須要的時候纔去加載數據;性能

  2. 數組和字典等集合類型還能夠防止爲初始化或者使用中被置爲 nilatom

  3. 類的屬性多了這麼寫看着更舒服、清晰
    。。。代理

基本上每一個屬性我都但願去懶加載實現它,這會給我一種錯覺:這樣寫更好,性能更高!code

其實,這是一個很差的習慣,隨着編程時間愈加的長,越是以爲以前有些偏激。對象

iOS 中懶加載的寫法通常爲重寫 getter 方法,判斷屬性是否爲 nil ,是的話去初始化,否就直接返回:

- (UIView *)layerView {
    if (!_layerView) {
        _layerView = [UIView new];
    }
    return _layerView;
}

可是咱們有更清晰、簡潔的寫法

通常來講,若是 layerView 是控制器的屬性,咱們通常都會在 viewDidLoad 方法中去加載視圖;若是是一個視圖,咱們通常會在 initWithFrame: 加載子視圖,咱們只須要安安靜靜的用如下代碼來初始化便可:

_layerView = [UIView new];

根本無需使用懶加載,由於若是你不是一我的在開發的話,你永遠不會知道你的隊友會在 get 方法裏面作什麼

並且這樣寫更簡潔,更清晰。當屬性不少的時候也可使用如下方式來初始化:

self.layerView = ({
    [UIView new];
});

用懶加載至少六行代碼,如今只須要一行或者三行就能夠作到。

咱們不能使用懶加載來防止那些可能出現的錯誤

很大一部分人用懶加載是爲了保證數組和字典等集合類型在使用中永遠不會是空值,這是錯誤的作法,由於可變集合類型被初始化以後,在正確的使用中若是不會被置 nil,那麼也無需使用懶加載。若是所以而引起的問題,也能夠幫咱們提早找到緣由。

對於耗時或性能很大的操做,咱們可使用惰性計算而不是懶加載

好比,我重構項目遇到的一個需求:請求股票列表返回的數據會告訴我總共會有上千條數據,而且不作分頁,就是所有展現,滑到第幾條就去請求第幾條的數據。

上千條數據不作分頁,咱們也不可能所有請求回來,即使能所有請求回來也不可能在一個方法裏去作這樣的操做:

NSMutableArray *dataArray = [NSMutableArray array];
for (int i = 0; i < 100000; ++i) {
  [dataArray addObject:data];
}

可是,對於 TableView 來說,上千條數據,固然須要 Array 的 count 返回是一千。這個時候咱們能夠用惰性計算來解決這個問題:有多少條數據,咱們就讓數組返回的 count 是多少,可是隻有真正的向數組取這個下標的對象的時候,咱們纔去處理!

那咱們繼承 NSArray 來寫(真正的寫一個 NSArray 還須要重寫其餘幾個方法,在此不細說):

typedef id(^HTLazyArrayItemBlock)(NSInteger index);
@interface HTLazyArray : NSArray
- (instancetype)initWithItemBlock:(HTLazyArrayItemBlock)block count:(NSInteger)count;
@end

#import "HTLazyArray.h"
@interface HTLazyArray()
@property (nonatomic, copy) HTLazyArrayItemBlock block;
@end

@implementation HTLazyArray {
    NSInteger _ct;
}
- (instancetype)initWithItemBlock:(HTLazyArrayItemBlock)block count:(NSInteger)count {
    if (self = [super init]) {
        _ct = count;
        self.block = block;
    }
    return self;
}
#pragma mark - override
- (NSUInteger)count {
    return _ct;
}
- (id)objectAtIndex:(NSUInteger)index {
    return self.block(index);
}
@end

咱們初始化的時候傳入一個 count,被 TableView 的代理方法訪問的時候,有則返回數據模型,沒有就先返回 nil,待到網絡請求到數據再進行刷新。這樣作的性能損耗微乎其微。

self.lazyArray = [[HTLazyArray alloc]initWithItemBlock:^id(NSInteger index) {
       HTQuoteAHCellModel *model = weakSefl.cache[@(index)];
       return model;
   } count:dataTotalCount];

那麼,咱們到底何時該用懶加載呢?

懶加載的使用須要看具體的場景,好比一個極可能不會被使用的屬性,使用懶加載確實能夠避免無所謂的性能損耗;
還有就是 null_resettable 修飾的屬性,該屬性意爲:setter nullable,可是 getter nonnull,典型的就是控制器的 view 屬性:「你能夠不要我,把我置空;但只要你須要我,我就是在的」。諸如此類均可以使用懶加載。

首發於https://iosgg.cn/2017/02/18/dont_abuse_lazy_load/

相關文章
相關標籤/搜索