在TableView中添加自定义Cell有三种方式:

  1. 纯代码实现Cell,不依赖xib或storyboard文件
  2. Storyboard + 代码的方式
  3. xib文件 + 代码的方式

##方式1: 纯代码实现Cell

###Step 1创建MyCell类

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

@interface MyCell : UITableViewCell
- (void)setTheValue:(NSString *)str;
@end

#import "MyCell.h"

@interface MyCell ()
@property (nonatomic, strong)UILabel *label;
@end

//MyCell.m
@implementation MyCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
    //创建内容组件
        _label = [[UILabel alloc] initWithFrame:CGRectMake(100, 0, 50, 50)];
        [self.contentView addSubview:_label];
    }
    return self;
}

- (void)setTheValue:(NSString *)str {
    NSString *text = _label.text;
    if(![str isEqualToString:text]) {
        _label.text = str;
    }
}
@end

Cell内部的内容组件都在initWithStyle: reuseIdentifier:方法中创建。

###Step 2添加TableView 在storyboard中添加一个TableView,并把其中的Cell删除。

###Step 3实现ViewController

//MyViewController.h
#import <UIKit/UIKit.h>
@interface MyViewController : UITableViewController
@end

//MyViewController.m
#import "MyViewController.h"
#import "MyCell.h"
@interface MyViewController ()
@property (nonatomic, copy) NSArray *dataSource;
@end

@implementation MyViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.dataSource = @[@"1", @"2", @"3"];
    
    //必须在这里注册才能确保重用cell
    [self.tableView registerClass:[MyCell class] forCellReuseIdentifier:@"CellIdentifier"];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataSource.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"];
    [cell setTheValue:[self.dataSource objectAtIndex:indexPath.row]];
    return cell;
}
@end

由于storyboard中并没有cell,因此必须在代码中注册自定义的cell,以实现cell重用。

方式2: storyboard + 代码

Step 1创建MyCell类

//MyCell.h
#import <UIKit/UIKit.h>
@interface MyCell : UITableViewCell
- (void)setTheValue:(NSString *)str;
@end

//MyCell.m
#import "MyCell.h"
@interface MyCell ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation MyCell
- (void)setTheValue:(NSString *)str {
    if(![_label.text isEqualToString:str]) {
        _label.text = str;
    }
}
@end

Cell的组件内容均在storyboard中实现,因此无需覆盖UITableViewCell的initWithStyle: reuseIdentifier:方法。

Step 2创建TableView和Cell

在storyboard中创建一个TableView,并设置Cell的Identifier和Cell的关联类(MyCell)。然后把一个UILabel拖入Cell中,作为Cell内容组件。最后把storyboard中的label与MyCell中的label通过ctrl-drag的方式连接起来。

Step 3实现ViewController

//MyViewController.h
#import <UIKit/UIKit.h>
@interface MyViewController : UITableViewController
@end

//MyViewController.m

#import "MyViewController.h"
#import "MyCell.h"
@interface MyViewController ()
@property (nonatomic, copy) NSArray *dataSource;
@end

//MyViewController.m
static NSString *CellIdentifier = @"CellIdentifier";
@implementation MyViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.dataSource = @[@"1", @"2", @"3"];
    
    //不要在这里注册cell!去storyboard中注册!
    //[self.tableView registerClass:[MyCell class] forCellReuseIdentifier:CellIdentifier];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataSource.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    NSString *str = [self.dataSource objectAtIndex:indexPath.row];
    [cell setTheValue:str];
    return cell;
}
@end

你只需在storyboard为自定义cell注册一次即可!!

注意,由于我们已经在storyboard中设置了cell的Identifier,因此切勿在代码中再对cell进行注册,因为这会导致Cell无法正常显示!!!

同时,你可能已经注意到,在storyboard中创建cell后,如果没有设置cell的identifier,编译器会给出警告。也就是说,在storyboard中创建cell时,编译器更希望你在storyboard设置cell的identifier,而不是在代码中注册。

方式3 xib + 代码

Step 1创建MyCell类

//MyCell.h
#import <UIKit/UIKit.h>
@interface MyCell : UITableViewCell
- (void)setTheValue:(NSString *)str;
@end

//MyCell.m
#import "MyCell.h"
@interface MyCell ()
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation MyCell
- (void)setTheValue:(NSString *)str {
    if(![_label.text isEqualToString:str]) {
        _label.text = str;
    }
}
@end

Cell的组件内容均在xib文件中实现,因此无需覆盖UITableViewCell的initWithStyle: reuseIdentifier:方法。

###Step 2创建TableView和Cell 在storyboard中创建一个TabelView,并删除其中的cell。

在项目创建一个名为CellXib的xib文件,用于表示cell。打开xib文件,往其中拖入一个label。

###Step 3创建ViewController

//MyViewController.h
#import <UIKit/UIKit.h>
@interface MyViewController : UITableViewController
@end

//MyViewController.m
#import "MyViewController.h"
#import "MyCell.h"
@interface MyViewController ()
@property (nonatomic, copy) NSArray *dataSource;
@end

static NSString *CellIdentifier = @"CellIdentifier";
@implementation MyViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.dataSource = @[@"1", @"2", @"3"];
    
    //仅需要在代码中注册一次
    UINib *nib = [UINib nibWithNibName:@"CellXib" bundle:nil];
    [self.tableView registerNib:nib forCellReuseIdentifier:CellIdentifier];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataSource.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MyCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    NSString *str = [self.dataSource objectAtIndex:indexPath.row];
    [cell setTheValue:str];
    return cell;
}
@end

与方式2不同的是,使用xib后,你只需用代码注册cell即可。

##总结 纯代码实现Cell

  • 优点: 我们可以复用这个cell。
  • 缺点: 在编写代码时,无法直观的看到cell的样子。
  • 只需要在代码中注册cell。
  • 不推荐使用

storyboard + 代码

  • 优点: 可以直观的看到cell嵌入到TabelView的效果,同时也方便对cell进行管理。
  • 缺点: 无法复用这个cell。因为cell和storyboard紧密关联。(storyboard的一大特点就是不能拥有独立, 可复用的view)
  • 只需要在storyboard中注册cell。
  • 当我们不需要复用cell时,可以选择此方法

xib文件 + 代码

  • 优点: 可以直观的看到cell的样子。
  • 需要同时管理storyboard和xib文件,有点麻烦。
  • 只需要在代码中注册cell。
  • 当我们需要复用cell时,可以选择此方法。