iOS 如何实现View的复用(以访问相册为例)

来源:互联网 发布:网站seo综合查询 编辑:程序博客网 时间:2024/05/23 01:21

原创Blog,转载请注明出处
http://blog.csdn.net/hello_hwc?viewmode=list
欢迎关注我的iOS SDK详解专栏
http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html


前言:Tableview可以加载很多数据,但是却不会引起内存问题,因为在加载Cell的时候,我们使用了这个方法 dequeueReusableCell......,这个方法就是使用了Cell的复用。同理,如果我们要实现自己的View加载很多东西的时候,View复用也是十分必要的,例如用ScrollView加载很多东西,如果不断的创建新的View,毫无疑问最后内存会不够用。


如何实现View复用?

我自己有三条规则

  1. 建立两个NSSet,一个代表复用池,一个代表可视池。
  2. 每当需要新的View时候,先检查复用池里有没有,如果有,则取出,没有则创建新的。
  3. 监听用户可视范围,需要新的View则按照2中的规则来得到一个新的View,如果一个View不可见了,则放到复用池里

一个简单的例子-访问相册
效果

这里写图片描述

先实现规则1
为了实现规则1,需要声明两个NSSet,当然我们也需要一个Scrollview和一个数据源

@property (strong,nonatomic)UIScrollView * containScrollView;@property (strong,nonatomic)NSMutableArray * assetsArray;@property (strong,nonatomic)NSMutableSet * dequePool;//复用池@property (strong,nonatomic)NSMutableSet * visiablePool;//可见池

并且对其初始化

    -(void)commonInit{    self.dequePool = [[NSMutableSet alloc] init];    self.visiablePool = [[NSMutableSet alloc] init];    _containScrollView = [[UIScrollView alloc] initWithFrame:CGRectIntegral([UIScreen mainScreen].bounds)];    _containScrollView.delegate = self;    _containScrollView.backgroundColor = [UIColor blackColor];    _containScrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;    _containScrollView.pagingEnabled = true;    _containScrollView.showsHorizontalScrollIndicator =  false;    _containScrollView.showsVerticalScrollIndicator = false;    self.automaticallyAdjustsScrollViewInsets = NO;    [self.view addSubview:_containScrollView];}-(void)awakeFromNib{    [self commonInit];}

然后实现规则2
因为要复用,所以要一个复用的类似UITableviewCell之类的View,这里我们继承UIImageView,实现一个带index和可以加载相册图片的ImageView
这个类的头文件

@class PHAsset;@interface LeoImageView : UIImageView@property (nonatomic,copy)NSNumber * index;@property (nonatomic,copy)PHAsset * asset;-(void)loadImage;@end

然后,写一个方法来实现规则2

-(LeoImageView *)generageDequeImageview{    LeoImageView * imageview = [self.dequePool anyObject];    if (imageview == nil) {        imageview = [[LeoImageView alloc] initWithFrame:_containScrollView.bounds];        imageview.contentMode = UIViewContentModeScaleAspectFit;    }else{        [self.dequePool removeObject:imageview];    }    return imageview;}

实现规则3
这里监听ScrollViewDidScroll

-(void)scrollViewDidScroll:(UIScrollView *)scrollView{    CGFloat scrollViewWidth = CGRectGetWidth(scrollView.frame);    CGFloat scrollViewHeight = CGRectGetHeight(scrollView.frame);    CGFloat startOrigin = scrollView.bounds.origin.x;    CGFloat endOrigin = scrollView.bounds.origin.x + scrollViewWidth;    //可视区域的开始    NSInteger startVisiableIndex = (NSInteger)floor(startOrigin/scrollViewWidth);    startVisiableIndex = [self IntegerShouldNotBeyoundBounds:startVisiableIndex];    //可视区域结束    NSInteger endVisiableIndex = (NSInteger)floor(endOrigin/scrollViewWidth);    endVisiableIndex = [self IntegerShouldNotBeyoundBounds:endVisiableIndex];    NSMutableSet * curVisiableSet = [[_visiablePool valueForKeyPath:@"index"] mutableCopy];    NSMutableSet * needVisiableSet = [self createSetWith:startVisiableIndex End:endVisiableIndex];    if ([curVisiableSet isEqualToSet:needVisiableSet] == false) {        if (curVisiableSet.count > needVisiableSet.count) {            //View可以被复用            [curVisiableSet minusSet:needVisiableSet];            for (LeoImageView * imageView in [_visiablePool copy]) {                if ([curVisiableSet containsObject:imageView.index]) {                    [imageView removeFromSuperview];                    imageView.image = nil;                    imageView.index = nil;                    [_visiablePool removeObject:imageView];                    [_dequePool addObject:imageView];                }            }        }else{            //需要新的View            [needVisiableSet minusSet:curVisiableSet];            for (NSNumber * index in needVisiableSet) {                LeoImageView * imageView = [self generageDequeImageview];                imageView.asset  = [self.assetsArray objectAtIndex:index.integerValue];                [imageView loadImage];                imageView.index = index;                imageView.frame = CGRectMake(index.integerValue * scrollViewWidth, 0, scrollViewWidth,scrollViewHeight);                [_containScrollView addSubview:imageView];                [_visiablePool addObject:imageView];            }        }    }}

这里有两个辅助方法

-(NSInteger)IntegerShouldNotBeyoundBounds:(NSInteger)number{    if (number < 0) {        number = 0;    }    if (number > self.assetsArray.count - 1) {        number = self.assetsArray.count - 1;    }    return number;}-(NSMutableSet *)createSetWith:(NSInteger)start End:(NSInteger)end{    NSMutableSet * set = [NSMutableSet new];    for (NSInteger index = start;index <= end;index++) {        [set addObject:@(index)];    }    return  set;}

然后,我们的复用架构就完成了。其他的代码就是访问图片了,注意Photo.h要求系统>8.0
完整工程可以在这里下载
http://download.csdn.net/detail/hello_hwc/9123757


0 0
原创粉丝点击