UITableView、UICollectionView等按需加載圖片(SDWebImage加載)

我們平常會涉及到很多展示圖片的,SDWebImage是我們常用的圖片加載框架,它非常簡單,基本一行代碼就能顯示圖片

[imageView sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder]

但是在網(wǎng)絡不好的情況下,圖片下載的速度完全跟不上我們滑動的速度,于是有了按需加載

按需加載有兩種方式:

第一種為:視圖出現(xiàn)時就會下載圖片,若是此圖片還未下載成功將此單元格滑出屏幕,會取消滑出圖片的下載轉(zhuǎn)而下載此時出現(xiàn)的單元格的圖片。

第二種為:視圖首次出現(xiàn)、停止拖拽、停止減速時就會下載圖片,若是此圖片還未下載成功將此單元格滑出屏幕,會取消滑出圖片的下載轉(zhuǎn)而下載此時出現(xiàn)的單元格的圖片。

由于tableView和collectionView的單元格重用機制,很容易造成圖片未下載完顯示錯亂,所以需要在自定義cell中重寫prepareForReuse方法,下面的imageVi為自定義UIImageView控件

vc.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    HKTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTableViewCellId forIndexPath:indexPath];
    cell.placeholderImage = self.placeholderImage;
    PersonModel *model = self.dataArr[indexPath.row];
    if (self.segmentControl.selectedSegmentIndex == 0) {//第一種
        cell.tableView = tableView;
        cell.indexPath = indexPath;
        cell.model = model;
    } else {//第二種
        cell.titleLabel.text = model.name;
        cell.imageVi.image = self.placeholderImage;
        UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:model.picture];
        if (cacheImage) {
            NSLog(@"圖片尺寸%@",NSStringFromCGSize(cacheImage.size));
            cell.imageVi.image = cacheImage;
        } else {
            if (!tableView.isDragging && !tableView.isDecelerating) {
                [cell.imageVi sd_setImageWithURL:[NSURL URLWithString:model.picture] placeholderImage:self.placeholderImage completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
                    image = [image drawImageWithSize:CGSizeMake(kSCREEN_WIDTH, 600)];
                    cell.imageVi.image = image;
                    [[SDImageCache sharedImageCache] storeImage:image forKey:model.picture completion:nil];
                }];
            }
        }
    }
    return cell;
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        if (self.segmentControl.selectedSegmentIndex == 1) {//適用于第二種
            [self loadImageForCellRows];
        }
    }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    if (self.segmentControl.selectedSegmentIndex == 1) {//適用于第二種
        [self loadImageForCellRows];
    }
}

#pragma mark - 加載圖片
- (void)loadImageForCellRows {
    NSArray *cells = [self.tableView indexPathsForVisibleRows];
    for (NSIndexPath * indexPath in cells) {
        HKTableViewCell *cell = (HKTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:self.dataArr[indexPath.row]];
        if (cacheImage) {
            cell.imageVi.image = cacheImage;
        } else {
            [cell.imageVi sd_setImageWithURL:[NSURL URLWithString:self.dataArr[indexPath.row]] placeholderImage:[UIImage imageNamed:@"placeholder"]];
        }
    }
}

cell.m

- (void)prepareForReuse {
    [super prepareForReuse];
    self.imageVi.image = self.placeholderImage;//占位圖需要,不然網(wǎng)絡很差時可看到顯示錯亂
    [self.imageVi sd_cancelCurrentImageLoad];//此方法作用是取消imageView以前關聯(lián)的url的下載
}

這兒模擬常規(guī)加載數(shù)據(jù)

- (void)setModel:(PersonModel *)model {
    _model = model;
    if (self.tableView && self.indexPath) {
        self.titleLabel.text = model.name;
        UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:model.picture];
        if (cacheImage) {
            self.imageVi.image = cacheImage;
            NSLog(@"圖片尺寸%@",NSStringFromCGSize(cacheImage.size));
        } else {
            NSArray *cells = [self.tableView indexPathsForVisibleRows];
            if ([cells containsObject:self.indexPath]) {
                [self.imageVi sd_setImageWithURL:[NSURL URLWithString:model.picture] placeholderImage:self.placeholderImage completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
                    image = [image drawImageWithSize:CGSizeMake(kSCREEN_WIDTH, 600)];
                    self.imageVi.image = image;
                    [[SDImageCache sharedImageCache] storeImage:image forKey:model.picture completion:nil];
                }];
            }
        }
    }
}

AppDelegate.m

為了避免加載大圖內(nèi)存暴漲crash,我這兒取消了SDWebImage的內(nèi)存緩存,只在disk緩存

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //下面兩行代碼主要是防止加載大分辨率圖片時內(nèi)存暴漲crash
    [SDImageCache sharedImageCache].config.shouldCacheImagesInMemory = NO;//緩存圖片不放入內(nèi)存
    //sd中可點擊diskCacheReadingOptions跳轉(zhuǎn)到這個屬性,提示設置為NSDataReadingMappedIfSafe可提高性能
    [SDImageCache sharedImageCache].config.diskCacheReadingOptions = NSDataReadingMappedIfSafe;
    
    return YES;
}

有時候圖片加載多了會出現(xiàn)內(nèi)存警告,所以還需要在AppDelegate.m中重寫下面的方法,內(nèi)存過高需要清理

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    [[SDWebImageManager sharedManager] cancelAll];
    [[SDWebImageManager sharedManager].imageCache clearWithCacheType:SDImageCacheTypeDisk completion:nil];
}

demo當然是不能少的啦,demo中圖片鏈接若是失效可自行裝載幾個圖片url(缺資源找度娘)

demo在這兒

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容