iOS cell重用

有一种需求,想必大家都遇到过..


简单的描述就是在 cell 上有个 button, 点击 button 出现勾选或者未勾选状态,但是如果不进行一些处理,就一定会出现重用的情况,所谓的重用也就是说由于 cell 的重用机制,导致 cell 上的 button 没办有办法正确的保存当前的点击状态,上网查了下,总结起来一共有三种方法,两种是和创建 cell 的方法有关,不过都比较消耗内存,还有一种好像是用数组进行记录(本人比较笨,至今未想明如何记录),在我看来这三种方法我都不太想去用,但是当我去研究数组记录这个方法时,我突然想到,由于现在基本都使用 MVC 模式开发,既然数据与模型已经分离,那为何不在数据里(model 里)记录,在模型上显示呢.... cell 上的 UI 是根据 model 进行排布的,这样的话就不会出现 cell 重用的情况了,而且一定能准确的记录点击状态

首先,大家准备个数据源,我这里的数据都是写在 plist (Student.plist)文件里了,然后就是相应的图片,都准备好了就可以往下看代码了


这里先创建个单利,用来取出 plist 文件中的数据(MyData)

//
//  MyData.h
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Student.h"
@interface MyData : NSObject

-(void)getAllStudentDic;
+(instancetype)shareMyDataHandle;
@property(nonatomic,retain)NSMutableDictionary *allStudentDic;
@property(nonatomic,retain)NSMutableArray *allKeysArray;

@end


//
//  MyData.m
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import "MyData.h"

@implementation MyData


+(instancetype)shareMyDataHandle
{
    static MyData *myData = nil;
    
    if (myData == nil) {
        
        myData = [[MyData alloc] init];
        [myData getAllStudentDic];
    }
    
    return myData;
  
}

-(void)getAllStudentDic
{
    self.allStudentDic = [NSMutableDictionary dictionary];
    
    
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Student" ofType:@"plist"];
    
    NSMutableDictionary *myDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
    
    for (NSString *key  in myDic.allKeys) {
        
        NSMutableArray *array = [myDic objectForKey:key];
        
        NSMutableArray *studentArray = [NSMutableArray array];
        
        for (NSDictionary *dic in array) {
            
            Student *stu = [[Student alloc] init];
            [stu setValuesForKeysWithDictionary:dic];
            
            [studentArray addObject:stu];
        }
        
        [self.allStudentDic setObject:studentArray forKey:key];
        
        
    }

    self.allKeysArray = [NSMutableArray arrayWithArray:self.allStudentDic.allKeys];
    [self.allKeysArray sortUsingSelector:@selector(compare:)];

  
}


@end

接下来是 model(Student)
//
//  Student.h
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface Student : NSObject

@property(nonatomic,copy)NSString *studentName;
@property(nonatomic,copy)NSString *phoneNumber;
@property(nonatomic,copy)NSString *contents;
@property(nonatomic,copy)NSString *picName;

@property(nonatomic,assign)BOOL selected;

@end
//
//  Student.m
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import "Student.h"

@implementation Student

-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
   
    
}

@end

有关于数据类型的类我们已经创建完成了,接下来是自定义 cell(MyTableViewCell)
//
//  MyTableViewCell.h
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "Student.h"

@protocol MyTableViewCellDelegate <NSObject>

-(void)studentInfo:(Student *)student;

@end

@interface MyTableViewCell : UITableViewCell

@property(nonatomic,retain)Student *stu;
@property(nonatomic,retain)UILabel *label;
@property(nonatomic,retain)UILabel *contentLable;
@property(nonatomic,retain)UIImageView *headImageView;

@property(nonatomic,retain)UIButton *button;
@property(nonatomic,assign)id<MyTableViewCellDelegate>MyCellDelegate;


+(CGFloat)heightForCell:(NSString *)content;

@end

//
//  MyTableViewCell.m
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import "MyTableViewCell.h"

@implementation MyTableViewCell


-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self) {
        
        [self createSubviews];
        
    }
    return self;
}
-(void)createSubviews
{
    self.label = [[UILabel alloc] initWithFrame:CGRectMake(70, 5, 200, 30)];
    [self.contentView addSubview:self.label];

    self.contentLable = [[UILabel alloc] initWithFrame:CGRectMake(70, 40, 300, 40)];
    self.contentLable.font = [UIFont systemFontOfSize:15.0];
    self.contentLable.numberOfLines = 0;
    [self.contentView addSubview:self.contentLable];

    self.headImageView = [[UIImageView alloc] initWithFrame:CGRectMake(5, 10, 60, 60)];
    [self.contentView addSubview:self.headImageView];


    self.button = [UIButton buttonWithType:UIButtonTypeCustom];
    self.button.frame = CGRectMake(330, 10, 24, 24);
    [self.button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.contentView addSubview:self.button];


}

-(void)buttonAction:(UIButton *)button
{

    if (self.stu.selected) {

        //2.点击按钮的时候加判断
        [self.button setBackgroundImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
        self.headImageView.hidden = NO;
        
    }else
    {
        [self.button setBackgroundImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
        self.headImageView.hidden = YES;
    }

    self.stu.selected = !self.stu.selected;

    [self.MyCellDelegate studentInfo:self.stu];
    
}

-(void)setStu:(Student *)stu
{

    if (_stu != stu) {
        _stu = stu;
    }
    //赋值
    self.label.text = _stu.studentName;
    self.contentLable.text = _stu.contents;
    CGRect frame = self.contentLable.frame;
    //计算高度
    frame.size.height = [[self class] heightForCell:_stu.contents];
    self.contentLable.frame = frame;
    UIImage *image = [UIImage imageNamed:_stu.picName];
    self.headImageView.image = image;

    //1.上拉下拉cell会重用cell,所以需要在赋值的时候加判断
    [self.button setBackgroundImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
    self.headImageView.hidden = NO;
    
    if (_stu.selected) {

        [self.button setBackgroundImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
        self.headImageView.hidden = YES;
    }


}

#pragma mark - cell 自适应高度
+(CGFloat)heightForCell:(NSString *)content
{

    CGSize size = CGSizeMake(300, 2000);
    NSDictionary *dic = [NSDictionary dictionaryWithObject:[UIFont systemFontOfSize:15.0] forKey:NSFontAttributeName];
    CGRect frame = [content boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:dic context:nil];
    
    return frame.size.height;
    
}

- (void)awakeFromNib {
    // Initialization code
    NSLog(@"aaaaa");
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
    NSLog(@"bbbbbbbbbbbb");
}

@end

到这里为止我们的 cell 重用已经解决了,之后就是在Controller 里使用了
//
//  RootViewController.h
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "MyData.h"
#import "MyTableViewCell.h"

@interface RootViewController : UIViewController<UITableViewDataSource,UITableViewDelegate,MyTableViewCellDelegate>


@property(nonatomic,retain)UITableView *myTableView;


@end

//
//  RootViewController.m
//  UI_Custom
//
//  Created by Amydom on 16/11/22.
//  Copyright (c) 2016年 Amydom. All rights reserved.
//

#import "RootViewController.h"

@interface RootViewController ()

@end

@implementation RootViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    self.myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds] style:UITableViewStylePlain];
    [self.view addSubview:self.myTableView];

    self.myTableView.delegate = self;
    self.myTableView.dataSource = self;

    
    
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return [[MyData shareMyDataHandle].allKeysArray objectAtIndex:section];
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSString *key = [[MyData shareMyDataHandle].allKeysArray objectAtIndex:section];
    NSMutableArray *array = [[MyData shareMyDataHandle].allStudentDic objectForKey:key];
    return array.count;
}

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [MyData shareMyDataHandle].allKeysArray.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    static NSString *cellIdentifier = @"cell";
    MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        
        cell = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

    }

    NSString *key = [[MyData shareMyDataHandle].allKeysArray objectAtIndex:indexPath.section];
    NSArray *array = [[MyData shareMyDataHandle].allStudentDic objectForKey:key];
    
    Student *stu = [array objectAtIndex:indexPath.row];
    cell.stu = stu;
    cell.MyCellDelegate = self;



    return cell;
}
-(void)studentInfo:(Student *)student
{
    NSLog(@"name = %@ contents = %@",student.studentName, student.contents);
}


//cell 高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *key = [[MyData shareMyDataHandle].allKeysArray objectAtIndex:indexPath.section];
    NSMutableArray *array = [[MyData shareMyDataHandle].allStudentDic objectForKey:key];
    Student *stu = [array objectAtIndex:indexPath.row];
    
    CGFloat height = [MyTableViewCell heightForCell:stu.contents];
    return height + 60;
    
}


-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];

}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end


这里解决cell 重用的方法可能比较局限,比如只能在 MVC 模式下使用,不过相对来说,这种方法基本上对内存不存在消耗现象,并且相对比较轻便,至于 cell 的自适应,由于篇幅的关系,这里只是对纯文本的数据进行了处理,下篇博客将会带来图文混排的 cell 自适应...





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值