我正在尝试实现this示例项目中显示的概念。我的目标是分离我的视图控制器类和数据源协议。我没有在我的表视图控制器类中实现表视图数据源方法,而是尝试将它放在自己的类中,在我的视图控制器中,我只调用此方法来设置我的表视图:
- (void)setupTableView
{
void (^configureCell)(JVRTodoItemCell *, JVRTodoItem *) = ^(JVRTodoItemCell *cell, JVRTodoItem *todoItem)
{
[cell configureForTodoItem:todoItem];
};
NSArray *todoItems = currentUser.todoItems;
self.todoArrayDataSource = [[JVRArrayDataSource alloc] initWithItems:todoItems withCellIdentifier:TodoCellIdentifier withConfigureCellBlock:configureCell];
self.tableView.dataSource = self.todoArrayDataSource;
[self.tableView registerClass:[JVRTodoItemCell class] forCellReuseIdentifier:TodoCellIdentifier];
}
数据源分为自己的类:
@interface JVRArrayDataSource ()
@property (copy,nonatomic) NSArray *items;
@property (copy,nonatomic) NSString *cellIdentifier;
@property (copy,nonatomic) void (^configureCellBlock)(id item, id cell);
@end
@implementation JVRArrayDataSource
...
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath];
self.configureCellBlock(cell,item);
return cell;
}
有趣的是,基于标识符创建单元格(使用dequeueReusableCellWithIdentifier:forIndexPath :)似乎是成功的,因为正确的单元格已分配,但其标签仍为零。我尝试使用以下方法设置我的单元格,但值仍为零(aTodoItem具有有效属性):
- (void)configureForTodoItem:(JVRTodoItem *)aTodoItem
{
self.todoItemTitle.text = aTodoItem.title;
self.todoItemPriority.text = [NSString stringWithFormat:@"%d", aTodoItem.priority];
}
我想弄清楚这里可能会遗漏什么,但到目前为止,我还没有设法解决这个问题,而我开始失去希望。任何帮助将不胜感激。
更新: 为清楚起见,问题显示在此图片上。
似乎细胞已经创建,但它的标签却没有。
答案 0 :(得分:1)
如果您只想将tableview数据源委托与视图控制器分开,则可以创建一个名为TableViewDataSource
的单独类。在该类中,您可以管理数据源及其表视图单元格;在视图控制器中配置它们,但让TableViewDataSource
管理它们。
<强> TDSTableViewDataSource.h 强>
#import <Foundation/Foundation.h>
@protocol TDSTableViewDataSourceDelegate <NSObject>
- (NSString *)fetchCellIdentifierForObject:(id)object;
- (UITableViewCell *)configureCell:(UITableViewCell *)cell usingObject:(id)item;
@end
@interface TDSTableViewDataSource : NSObject <UITableViewDataSource>
@property (strong, nonatomic) NSArray *items;
@property (strong, nonatomic) id<TDSTableViewDataSourceDelegate> delegate;
@end
<强> TableViewDataSource.m 强>
#import "TDSTableViewDataSource.h"
@implementation TDSTableViewDataSource
- (NSArray *)items {
if (!_items) _items = [[NSArray alloc] init];
return _items;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if ([self.items count]) {
return [self.items count];
} else {
NSLog(@"numberOfSectionsInTableView could not be determined. self.items is nil or empty.");
return 0;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([self.items count]) {
return [self.items count];
} else {
NSLog(@"numberOfRowsInSection could not be determined. self.items contains fewer section requested does not contain any items.");
return 0;
}
}
/*
Single dimension Array of items belonging to a UITableView section
The method checks if the cell implements the HZConfigureTableViewCellDelegate, which is required.
The delegate should be the View Controller.
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id obj = [self.items objectAtIndex:indexPath.row];
UITableViewCell *cell = nil;
if ([self.delegate conformsToProtocol:@protocol(TDSTableViewDataSourceDelegate)]) {
NSString *cellIdentifier = [self.delegate fetchCellIdentifierForObject:obj];
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (obj)
cell = [self.delegate configureCell:cell usingObject:obj];
}
return cell;
}
@end
这个类和协议基本上允许你获取和配置UITableViewCell
,而不必在视图控制器中实现协议。
在视图控制器中,您可以使用上面的协议创建数据源属性。
#import "TDSViewController.h"
#import "TDSTableViewDataSource.h"
@interface TDSViewController () <UITableViewDelegate, TDSTableViewDataSourceDelegate>
@property (strong, nonatomic) TDSTableViewDataSource *dataSource; // UITableView data source.
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
@implementation TDSViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.dataSource = self.dataSource;
self.dataSource.delegate = self;
}
#pragma mark - UITableView methods
-(NSString *)fetchCellIdentifierForObject:(id)object {
// Check if this is an event or a Reminder class.
if ([object isKindOfClass:[UITableViewCell class]]) {
// Return the cell identifier for this particular cell.
return @"com.myapp.defaultcell";
}
return @"blankcell";
}
- (UITableViewCell *)configureCell:(UITableViewCell *)cell usingObject:(id)item {
UITableViewCell *configuredCell = cell;
// Check if this is an event or a reminder.
if ([item isKindOfClass:[UITableViewCell class]]) {
// Configure the cell to present what data we want here...
}
return configuredCell;
}
@end
这是一个完整的示例项目。您可以使用它来配置所需的任何类型的单元格,而无需将数据源方法添加到视图控制器。
ConfigureTableViewCellDelegate
协议使用视图控制器来配置UITableViewCell
并在表视图中使用它们。由于代码现在是隔离的,TableViewDataSource
类现在处理将数据呈现给表视图。 View Controller仅用于配置单元。如果需要,这允许您在每个ViewController上使用自定义UITableViewCells,而不必每次都处理实现数据源。
<强>已更新强>
提供了一个更好的例子,一个完整的项目模板。
答案 1 :(得分:1)
在ViewDidLoad注册nib中,它解决了问题:)
-(void)viewDidLoad
{
[self.leftTableView registerNib:[UINib nibWithNibName:NIB_FILE bundle:nil] forCellReuseIdentifier:CELL_IDENTIFIER];
}
答案 2 :(得分:0)
经过几个小时的挖掘,我设法解决了这个问题(现在),将自定义单元的出口更改为强属性,并在单元的init方法中初始化它们:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.todoItemTitle = [[UILabel alloc] init];
self.todoItemPriority = [[UILabel alloc] init];
}
return self;
}
这很奇怪,因为我认为在故事板中创建我的观点,这应该自动处理,我从来没有必须手动执行此操作。