iOS开发之UICollectionViewDataSourcePrefetching

在iOS10中,苹果为UICollectionViewCell引入了Pre-Fetching预加载机制用于提升它的性能。主要引入了一个新的数据源协议UICollectionViewDataSourcePrefetching,包含两个方法:

@protocol UICollectionViewDataSourcePrefetching <NSObject>
@required
// 预加载数据
- (void)collectionView:(UICollectionView *)collectionView prefetchItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths NS_AVAILABLE_IOS(10_0);
@optional
// 取消提前加载数据
- (void)collectionView:(UICollectionView *)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths  NS_AVAILABLE_IOS(10_0);
@end
复制代码

网上搜了一大圈,讲述原理的(翻译文档)的文章很多,有干货的Demo很少,于是乎自己摸索了一下,写了一个简单的案例,在此记录并分享一下。

运行环境:Xcode 8.2.1 + iOS 10.2

核心步骤:

1、遵从 UICollectionViewDataSourcePrefetching 协议 2、实现 collectionView:prefetchItemsAtIndexPaths 方法和collectionView:cancelPrefetchItemsAtIndexPaths 方法(可选) 3、将第1步中遵从协议的类设置为 UICollectionView 的 prefetchDataSource 属性

实现

一、创建UICollectionViewFlowLayout

自己写一个类继承自UICollectionViewFlowLayout

@implementation MyCollectionViewFlowLayout

-(void)prepareLayout{

    self.minimumLineSpacing = 1;//垂直间距
    self.minimumInteritemSpacing = 0;//水平间距
    self.sectionInset = UIEdgeInsetsMake(0, 0, 8, 0);//分组间距

}
@end
复制代码
二、用XIB定义一个

里面就一个UIImageView,然后拽线设置一个IBOutlet

@property (weak, nonatomic) IBOutlet UIImageView *imgView;
复制代码
三、控制器

注释很详细

#import "ViewController.h"
#import "MyCollectionViewFlowLayout.h"
#import "ImgCollectionViewCell.h"

#define ScreenW [UIScreen mainScreen].bounds.size.width
//重用标识
static NSString *cellId = @"imgCell";
//遵守协议
@interface ViewController ()<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDataSourcePrefetching>

//下载图片任务
@property(nonatomic, strong) NSMutableDictionary<NSURL *, dispatch_queue_t> *tasks;
//图片地址
@property(nonatomic, copy) NSMutableArray<NSURL *> *imgURLArray;
//下载的图片
@property(nonatomic, copy) NSMutableDictionary<NSURL *, UIImage *> *imgs;
//UICollectionView
@property(nonatomic, weak) UICollectionView *collectionView;

@end

@implementation ViewController

//懒加载imgURLArray
-(NSMutableArray<NSURL *> *)imgURLArray{
    
    if (_imgURLArray == nil) {   
        _imgURLArray = [NSMutableArray array];    
        for (int i = 0; i < 30; i++) {
            NSURL *imgURL = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494499175005&di=1d8d40ac84f4a71cb26d7bf4a5a845ec&imgtype=0&src=http%3A%2F%2Fimg10.360buyimg.com%2Fyixun_zdm%2Fjfs%2Ft2830%2F11%2F2310606472%2F165925%2F962fa94a%2F575f7664Nfd743845.jpg"];
            [_imgURLArray addObject:imgURL];            
        }
    }
    
    return _imgURLArray;    
}

//懒加载imgs
-(NSMutableDictionary<NSURL *,UIImage *> *)imgs{
    if (_imgs == nil) {        
        _imgs = [NSMutableDictionary dictionary];
    }   
    return _imgs;
}

//懒加载tasks
-(NSMutableDictionary<NSURL *,dispatch_queue_t> *)tasks{
    if (_tasks == nil) {       
        _tasks = [NSMutableDictionary dictionary];
    }   
    return _tasks;   
}


- (void)viewDidLoad {
    [super viewDidLoad];
    
    //创建UICollectionView
    //创建布局
    UICollectionViewLayout *layout = [[MyCollectionViewFlowLayout alloc]init];
    //初始化一个UICollectionView
    UICollectionView *collection = [[UICollectionView alloc]initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
    //设置背景色
    collection.backgroundColor = [UIColor groupTableViewBackgroundColor];
    //设置代理
    collection.dataSource = self;
    collection.delegate = self;
    collection.prefetchDataSource = self;
    //注册Cell
    UINib *nib = [UINib nibWithNibName:@"ImgCollectionViewCell" bundle:nil];
    [collection registerNib:nib forCellWithReuseIdentifier:cellId];
     
    [self.view addSubview:collection];
    
    self.collectionView = collection;
    
}


-(void)loadImage:(NSIndexPath *)indexPath{
    
    NSURL *currentURL = [self.imgURLArray objectAtIndex:indexPath.row];
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
    __weak typeof(self) weakSelf = self;
    
    //异步下载图片
    dispatch_async(queue, ^{
      
        NSData *imageData = [NSData dataWithContentsOfURL:currentURL];
        UIImage *image = [UIImage imageWithData:imageData];
        weakSelf.imgs[currentURL] = image;
        
        //更新UI   
         dispatch_async(dispatch_get_main_queue(), ^{
            
            ImgCollectionViewCell *cell = (ImgCollectionViewCell *)[weakSelf.collectionView cellForItemAtIndexPath:indexPath];
            cell.imgView.image = image;
        });
    });
    
    //为了取消任务
    self.tasks[currentURL] = queue;
    
}

#pragma mark <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    
    return self.imgURLArray.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
     
    ImgCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];
    
    // 获取URL
    NSURL *imgURL = self.imgURLArray[indexPath.row];
    
    //对应的URL的图片已经存在
    if (self.imgs[imgURL]) {        
        cell.imgView.image = self.imgs[imgURL];
    }
    //不存在
    else{
        
        [self loadImage:indexPath];
    }
    
    return cell;
    
}


#pragma mark <UICollectionViewDelegate>
//定义每个Item 的大小
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 
    CGFloat W = (ScreenW - 1) / 2;    
    return CGSizeMake(W, 100);
    
}

#pragma mark <UICollectionViewDataSourcePrefetching>
- (void)collectionView:(UICollectionView *)collectionView prefetchItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
    
    for (NSIndexPath * indexPath in indexPaths) {
        
        NSURL *currentURL = [self.imgURLArray objectAtIndex:indexPath.row]; 
        //不存在就请求
        if (!self.imgs[currentURL]) {
            [self loadImage:indexPath];
        }
    }
    
}


- (void)collectionView:(UICollectionView *)collectionView cancelPrefetchingForItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
    
    for (NSIndexPath * indexPath in indexPaths){
        
        NSURL *currentURL = [self.imgURLArray objectAtIndex:indexPath.row];  
        //当前任务存在
        if (self.tasks[currentURL]) {
            dispatch_queue_t queue = self.tasks[currentURL];
            dispatch_suspend(queue);
            self.tasks[currentURL] = nil;
        }
    }
    
}

@end

复制代码
效果

写在后面的话

1、这个新特性仍然需要探究 2、遇到的一个坑:细心看的话可以发现我的字典是懒加载的,如果直接在viewDidLoad中初始化会在 weakSelf.imgs[currentURL] = image; 一行报错,why?烦请知道的告知。

源代码

转载于:https://juejin.im/post/5a31138c5188252ae93af174

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS开发中,触摸事件处理是非常重要的,因为用户与应用程序的交互主要是通过触摸屏幕来完成的。iOS提供了一整套触摸事件处理机制,包括手势识别、触摸事件响应等。下面我们来介绍一下iOS中常用的触摸事件处理方法。 1. 触摸事件响应方法 在iOS中,触摸事件主要由以下4个方法来响应: - touchesBegan:withEvent: //手指开始接触屏幕 - touchesMoved:withEvent: //手指在屏幕上移动 - touchesEnded:withEvent: //手指离开屏幕 - touchesCancelled:withEvent: //触摸事件取消 这些方法都在UIView类中定义,所以如果你的应用程序需要响应触摸事件,你需要重写UIView的这些方法。 2. 手势识别器 在iOS中,手势识别器是一种非常方便的触摸事件处理方式。手势识别器可以识别出一些常用的手势,比如轻击、长按、拖动、捏合等等,并且可以通过回调方法来处理这些手势。 手势识别器有很多种,比如UITapGestureRecognizer、UILongPressGestureRecognizer、UIPanGestureRecognizer、UIPinchGestureRecognizer等等。使用手势识别器可以让你的应用程序更加灵活,同时也可以提高用户体验。 3. 响应者链 在iOS中,事件的传递是通过响应者链来完成的。当用户发生了触摸事件时,事件会从最上层的UIWindow开始传递,直到找到第一个响应该事件的对象。如果没有任何对象响应该事件,事件就会被丢弃。 因此,在处理触摸事件时,你需要注意响应者链的结构,确保事件能够正确地传递到你想要处理事件的对象。 总之,在iOS开发中,触摸事件处理是一个非常重要的部分,需要我们认真对待。通过合理地使用触摸事件处理方法和手势识别器,我们可以为用户提供更加灵活、友好的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值