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