您的位置:首页 > 移动开发 > IOS开发

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

2015-09-21 13:41 465 查看
原创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复用?

我自己有三条规则

建立两个NSSet,一个代表复用池,一个代表可视池。

每当需要新的View时候,先检查复用池里有没有,如果有,则取出,没有则创建新的。

监听用户可视范围,需要新的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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: