UITableViewCell复用可能会带来的问题

说到UITableViewCell,我们都了解它的复用机制,现在将UITableViewCell的复用机制总结一下。总的来说,UITableViewCell的复用机制有三种方法。

<.1.>
-(void)registerNib:(UINib*)nibforCellReuseIdentifier:(NSString*)identifierNS_AVAILABLE_IOS(5_0);

<.2.>-(void)registerClass:(Class)cellClassforCellReuseIdentifier:(NSString*)identifierNS_AVAILABLE_IOS(6_0);
当tableView调用以上两个方法进行注册的时候,就可以省去
TestTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identifer];
         if (!cell) {
         cell=[[TestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifer];
         }类似的这些代码。可以直接调用
-(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0); 这个方法就可以使用了。

<.3.>就是我们正常用的下面的代码
TestTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identifer];
         if (!cell) {
         cell=[[TestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifer];
具体使用的习惯就因人而异了。

三种方法介绍完毕,现在给出具体出现问题的案例。


UITableView的代码
.h文件中的代码
#import <UIKit/UIKit.h>

@interface TestTableView : UITableView

+(id)testTableViewWithFrame:(CGRect)frame;

@end
.m文件中的代码
#define identifer @"TestTableViewCell"

#import "TestTableView.h"
#import "TestTableViewCell.h"

@interface TestTableView()<UITableViewDelegate,UITableViewDataSource>


@end

@implementation TestTableView

+(id)testTableViewWithFrame:(CGRect)frame
{
    return [[TestTableView alloc] initWithFrame:frame style:UITableViewStylePlain];
}

-(id)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
    if (self=[super initWithFrame:frame style:style]) {
        self.backgroundColor=[UIColor whiteColor];
        self.dataSource=self;
        self.delegate=self;
    }
    return self;
}

#pragma mark UITableViewDataSource

-(NSInteger)numberOfSections
{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 40;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TestTableViewCell *cell=[TestTableViewCell testTableViewCellWithTableView:tableView];
    cell.indexPath=indexPath;
    return cell;
}

#pragma mark UITableViewDelegate

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 44.0f;
}

UITableViewCell的代码

.h文件中的代码

#import <UIKit/UIKit.h>

@interface TestTableViewCell : UITableViewCell

@property(nonatomic,weak)NSIndexPath *indexPath;

+(id)testTableViewCellWithTableView:(UITableView *)tableView;

@end

.m文件中的代码

#define identifer @"TestTableViewCell"

#import "TestTableViewCell.h"

@interface TestTableViewCell()

@property(nonatomic,strong)UIButton *testBtn;

@end

@implementation TestTableViewCell


#pragma mark Init Method

+(id)testTableViewCellWithTableView:(UITableView *)tableView
{
    TestTableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identifer];
    if (!cell) {
        cell=[[TestTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifer];
    }
    return cell;
}

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self=[super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
        self.contentView.backgroundColor=[UIColor whiteColor];
        [self.contentView addSubview:self.testBtn];
    }
    return self;
}

#pragma mark Get Method

-(UIButton *)testBtn
{
    if (!_testBtn) {
        _testBtn=[UIButton buttonWithType:UIButtonTypeSystem];
        _testBtn.frame=CGRectMake(([UIScreen mainScreen].bounds.size.width-100)/2, 0, 100, 44);
        _testBtn.backgroundColor=[UIColor blackColor];
        [_testBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    }
    return _testBtn;
}

#pragma mark Set Methd

-(void)setIndexPath:(NSIndexPath *)indexPath
{
    _indexPath=indexPath;
    if (_indexPath.row==8||_indexPath.row==16||_indexPath.row==20||_indexPath.row==25||_indexPath.row==30||_indexPath.row==35||_indexPath.row==40) {
        [self.testBtn setTitle:@"邀请" forState:UIControlStateNormal];
        [self.testBtn addTarget:self action:@selector(inviteMethod:) forControlEvents:UIControlEventTouchUpInside];
    }else{
        [self.testBtn setTitle:@"添加" forState:UIControlStateNormal];
        [self.testBtn addTarget:self action:@selector(addMethod:) forControlEvents:UIControlEventTouchUpInside];
    }
}

#pragma mark Private Method

-(void)inviteMethod:(UIButton *)sender
{
    NSLog(@"邀请");
}

-(void)addMethod:(UIButton *)sender
{
    NSLog(@"添加");
}

- (void)awakeFromNib {
    [super awakeFromNib];
}

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

@end

下面是程序截图:

首先是我们没有滚动这个tableView,cell里面的点击事件都是正常的,

150815_hc05_2364452.png

150921_SaB1_2364452.png

当我们开始上下来回滚动之后,再点击cell里面的button,这时候就会出现异常。

151056_iua4_2364452.png

一个我们在项目开发中,很容易就会遇到的类似问题,尤其是初学者。这个问题追根究底还是tableViewCell在复用的时候出现了问题。cell在复用的时候拿到了缓存池中的一个cell,而这个cell的子视图中含有另一个点击事件的button,此时你再给这个按钮添加另一个点击事件,最后就会导致这个按钮同时拥有两个点击事件。为了避免这个问题的存在,在给这个按钮添加新的点击事件之前,先判断该按钮是否含有其它的点击事件,若有,则移除其它的点击事件再添件新的点击事件;若无,直接添加新的点击事件。

转载于:https://my.oschina.net/Atoman/blog/687693

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值