PhotoKit制作相冊或選擇器(四):預(yù)加載策略

前言

上一篇文章里我們已經(jīng)將圖片選擇器的基本功能完成了文兑。相冊里圖片比較多的小伙伴有沒有覺得上下滾動起來不是很順呢(當(dāng)然夕膀,像小編這種屌絲挫男可能不會有這煩惱,相冊空空如也园爷,沒有自拍就沒有噩夢),那怎么來處理這種同時(shí)請求巨巨巨巨巨多圖片的情況呢,這里Apple API里給我們指了條路(蹩腳英文得派上場了LOOOOOOOOOOL


如果需要同時(shí)加載多個(gè)資源的圖片數(shù)據(jù)宪潮,使用PHCachingImageManager類通過加載你馬上想要的圖片來“預(yù)加載”緩存。打個(gè)比方戈抄,在一個(gè)顯示圖片資源縮略圖的collection view內(nèi),你可以在滾動到當(dāng)前位置前就緩存好圖片后专。

使用這些類來請求有關(guān)Photos資源的圖片划鸽,視頻,活圖內(nèi)容戚哎。
Photos框架根據(jù)你的要求自動下載并生成圖片裸诽,緩存它們,為了更快的復(fù)用型凳。為了大量資源能更快地表現(xiàn)丈冬,你也可以批請求預(yù)加載圖片。

那現(xiàn)在的思路就是在UICollectionView滾動前甘畅,先緩存可能顯示的圖片殷蛇,也就是當(dāng)前可顯示區(qū)域前后將要顯示的圖片实夹。

開始

定義所需屬性

//緩存圖片管理器
@property (nonatomic, strong) PHCachingImageManager *imageManager;
//先前預(yù)加載區(qū)域,用于比較
@property CGRect previousPreheatRect;

更新緩存

  1. 判斷界面是否顯示
  2. 初始化預(yù)加載區(qū)域大小粒梦,在可顯示區(qū)域基礎(chǔ)上前后各增加個(gè)可顯示區(qū)域
  3. 當(dāng)滾動范圍大于當(dāng)前顯示界面的三分之一時(shí),進(jìn)行緩存操作(由于此方法會在scrollview的代理方法scrollViewDidScroll:中調(diào)用荸实,頻繁調(diào)用會影響性能匀们,這里的規(guī)則可以根據(jù)需求進(jìn)行調(diào)控)
  4. 區(qū)別新增資源以及移除資源,進(jìn)行緩存更新
- (void)updateCachedAssets {
    BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil;
    if (!isViewVisible) { return; }
    
    // 預(yù)加載區(qū)域是可顯示區(qū)域的兩倍
    CGRect preheatRect = self.collectionView.bounds;
    preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect));
    
    //     比較是否顯示的區(qū)域與之前預(yù)加載的區(qū)域有不同
    CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));
    if (delta > CGRectGetHeight(self.collectionView.bounds) / 3.0f) {
        
        // 區(qū)分資源分別操作
        NSMutableArray *addedIndexPaths = [NSMutableArray array];
        NSMutableArray *removedIndexPaths = [NSMutableArray array];
        
        [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) {
            NSArray *indexPaths = [self indexPathsForElementsInCollectionView:self.collectionView rect:removedRect];
            [removedIndexPaths addObjectsFromArray:indexPaths];
        } addedHandler:^(CGRect addedRect) {
            NSArray *indexPaths = [self indexPathsForElementsInCollectionView:self.collectionView rect:addedRect];
            [addedIndexPaths addObjectsFromArray:indexPaths];
        }];
        
        NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];
        NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];
        
        // 更新緩存
        [self.imageManager startCachingImagesForAssets:assetsToStartCaching
                                            targetSize:AssetGridThumbnailSize
                                           contentMode:PHImageContentModeAspectFill
                                               options:nil];
        [self.imageManager stopCachingImagesForAssets:assetsToStopCaching
                                           targetSize:AssetGridThumbnailSize
                                          contentMode:PHImageContentModeAspectFill
                                              options:nil];
        
        // 存儲預(yù)加載矩形已供比較
        self.previousPreheatRect = preheatRect;
    }
}
  • 此方法是區(qū)分增加的區(qū)域以及減少的區(qū)域
- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler {
    if (CGRectIntersectsRect(newRect, oldRect)) {
        CGFloat oldMaxY = CGRectGetMaxY(oldRect);
        CGFloat oldMinY = CGRectGetMinY(oldRect);
        CGFloat newMaxY = CGRectGetMaxY(newRect);
        CGFloat newMinY = CGRectGetMinY(newRect);
        
        if (newMaxY > oldMaxY) {
            CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));
            addedHandler(rectToAdd);
        }
        
        if (oldMinY > newMinY) {
            CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));
            addedHandler(rectToAdd);
        }
        
        if (newMaxY < oldMaxY) {
            CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));
            removedHandler(rectToRemove);
        }
        
        if (oldMinY < newMinY) {
            CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));
            removedHandler(rectToRemove);
        }
    } else {
        addedHandler(newRect);
        removedHandler(oldRect);
    }
}

- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths {
    if (indexPaths.count == 0) { return nil; }
    
    NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];
    for (NSIndexPath *indexPath in indexPaths) {
        PHAsset *asset = self.assetsFetchResults[indexPath.item];
        [assets addObject:asset];
    }
    
    return assets;
}
  • 此方法作用是獲取某區(qū)域內(nèi)元素的indexPaths
- (NSArray *)indexPathsForElementsInCollectionView:(UICollectionView *)collection rect:(CGRect)rect {
    NSArray *allLayoutAttributes = [collection.collectionViewLayout layoutAttributesForElementsInRect:rect];
    if (allLayoutAttributes.count == 0) { return nil; }
    NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count];
    for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) {
        NSIndexPath *indexPath = layoutAttributes.indexPath;
        [indexPaths addObject:indexPath];
    }
    return indexPaths;
}
  • 界面顯示時(shí)需第一次更新緩存
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    // 可見區(qū)域刷新緩存
    [self updateCachedAssets];
}
  • UICollectionView滾動時(shí)更新緩存
#pragma mark -- UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    [self updateCachedAssets];
}

上一篇我們實(shí)現(xiàn)了相冊變化的檢測准给,那么如果相冊資源變化了泄朴,緩存如何操作呢?
這里小編直接將緩存重置露氮,簡單粗暴~

- (void)resetCachedAssets {
    [self.imageManager stopCachingImagesForAllAssets];
    self.previousPreheatRect = CGRectZero;
}

是不是覺得已經(jīng)大功告成了祖灰?其實(shí)還有個(gè)很重要的地方要改,不然就白忙活了畔规!
-collectionView:collectionView cellForItemAtIndexPath:這個(gè)代理方法內(nèi)局扶,我們請求圖片使用的[PHImageManager defaultManager]換成self.imageManager。因?yàn)槲覀兪褂玫氖谴藢ο髞磉M(jìn)行一系列緩存操作的叁扫。

附上DEMO

結(jié)束語

這個(gè)簡單的選擇器功能還不夠完善三妈,主要是熟悉Photos框架,如果讀者感興趣的話莫绣,可以持續(xù)關(guān)注小編的ASImagePicker

ASImagePicker持續(xù)更新中...
https://github.com/alanshen0118/ASImagePicker

文章中有任何錯(cuò)誤希望讀者能積極指出畴蒲,我會及時(shí)更正。
如果喜歡对室,請持續(xù)關(guān)注模燥,順便點(diǎn)個(gè)喜歡噢??????幫五菱加加油~@_@

Thanks!!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市掩宜,隨后出現(xiàn)的幾起案子蔫骂,更是在濱河造成了極大的恐慌,老刑警劉巖锭亏,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纠吴,死亡現(xiàn)場離奇詭異,居然都是意外死亡慧瘤,警方通過查閱死者的電腦和手機(jī)戴已,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锅减,“玉大人糖儡,你說我怎么就攤上這事≌唬” “怎么了握联?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵桦沉,是天一觀的道長。 經(jīng)常有香客問我金闽,道長纯露,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任代芜,我火速辦了婚禮埠褪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挤庇。我一直安慰自己钞速,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布嫡秕。 她就那樣靜靜地躺著渴语,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昆咽。 梳的紋絲不亂的頭發(fā)上驾凶,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音潮改,去河邊找鬼狭郑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛汇在,可吹牛的內(nèi)容都是我干的翰萨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼糕殉,長吁一口氣:“原來是場噩夢啊……” “哼亩鬼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阿蝶,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤雳锋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后羡洁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玷过,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年筑煮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辛蚊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡真仲,死狀恐怖袋马,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秸应,我是刑警寧澤虑凛,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布碑宴,位于F島的核電站,受9級特大地震影響桑谍,放射性物質(zhì)發(fā)生泄漏延柠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一锣披、第九天 我趴在偏房一處隱蔽的房頂上張望捕仔。 院中可真熱鬧,春花似錦盈罐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至悄蕾,卻和暖如春票顾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背帆调。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工奠骄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人番刊。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓含鳞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親芹务。 傳聞我的和親對象是個(gè)殘疾皇子蝉绷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容