我有一个genericTableViewController
- GTBVC
- 类,它被当前另外两个视图控制器所引导,每个视图控制器都有自己的数据数组,并传递给这个GTBVC
。
目前我的代码如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
id object = [self.genericArray objectAtIndex:indexPath.row];
NSString *textNameOfObject = [[self.genericArray objectAtIndex:indexPath.row] performSelector:@selector(name)];
#warning - todo: Create a polymorphistic method for each uitableviewcells.
if([object isMemberOfClass:[OXPersonModel class]]){
OXFriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTableViewCellFriendIdentifier forIndexPath:indexPath];
cell.friendNameLabel.text = textNameOfObject;
[PKQuickMethods setCornerRadiusForView:cell.friendImageView withCornerRadius:CGRectGetWidth(cell.friendImageView.frame)/2];
cell.friendImageView.image = [UIImage imageNamed:@"image"];
[cell.friendImageView setContentMode:UIViewContentModeScaleToFill];
return cell;
}
else if([object isMemberOfClass:[OXTagPlaceCountModel class]]){
OXTagTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTableViewCellTagIdentifier forIndexPath:indexPath];
cell.tagNameLabel.text = textNameOfObject;
cell.tagPlacesCountLabel.text = [[self.genericArray objectAtIndex:indexPath.row] performSelector:@selector(totalPlacesCountString)];
return cell;
}
return nil;
}
到目前为止,这种方法并不太糟糕。但是,因为我希望我的代码可以在未来扩展 - 当我扩展程序以满足其他单元格和产品类型时 - 我需要确保它易于实现。
我想到了多态性。我在想每个UITableView子类都需要实现一个公共方法名称,例如-[cell updateForModelObject:]
,这样最终cellForRowAtIndexPath
只会有几行代码。
但是我发现自己想象我仍然需要根据标识符确定哪些单元格出列。要出列的单元格取决于self.genericArray
中的对象类型。
如何在不使用任何if语句的情况下在cellForRowAtIndexPath
多态内部创建当前代码?
答案 0 :(得分:3)
您所描述的方法通常可以使用协议来实现。以下是:
在您的GTBVC标头中,声明一个协议,例如:
@protocol GTBVCCellConfiguration
-(void)updateForModelObject:(id)anObject;
@end
然后创建您的UITableViewCell子类,使它们符合该协议并让它们实现该方法。在子类中,您可以换出" id"您期望的实际数据类型的参数类型。
由于您的通用表视图控制器将处理不同类型的数据,您可以声明一个Enum来指定您的通用tableview控制器可以采用的各种模式:
typedef NS_ENUM(NSInteger, GenericTableViewMode) {
case GenericTableViewModePerson,
case GenericTableViewModePlace
};
然后在您的GTBVC标题中,声明该类型的属性:
@property (assign, nonatomic) GenericTableViewMode tableViewMode
在馈线视图控制器中,导入该GTBVC标头并实现准备segue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#yourSegueIdentifierForPerson#]) {
((GenericTableViewController *)segue.destinationViewController).mode = GenericTableViewModePerson;
} else {
// check for the next storyboard identifier and set the mode
}
}
然后在你的cellForRowAtIndexPath中(用一些简写):
-(void)tableView:cellForRowAtIndexPath: {
id object = [self.genericArray objectAtIndex:indexPath.row];
UITableViewCell <GTBVCellConfiguration> *cell = nil;
switch (self.mode) {
case GenericTableViewModePerson:
cell = [tableView dequeueResuableCellWithIdentifier:@"PERSON" forIndexPath:indexPath];
case GenericTableViewModePlace:
cell = [tableView dequeueResuableCellWithIdentifier:@"PLACE" forIndexPath:indexPath];
}
[cell updateForModelObject:object];
return cell;
}
如果您愿意,您甚至可以创建一个方法,为tableview的当前模式返回正确的标识符。
答案 1 :(得分:1)
我的建议还包括protocol
,而是您在模型对象上放置的协议。它可以有一个像-(NSString*)cellIdentifier
这样的方法,它返回该模型类的唯一标识符。然后,您只需通过获取该索引的模型对象从表视图中出列。此外,您可以在模型协议上定义单元用于配置的方法。
这意味着您可以定义任何符合此协议的对象,现在可以在任何地方使用您的单元格。
答案 2 :(得分:0)
使用convention over configuration并按照模型类型确定的方式命名您的单元格标识符,例如,
NSString *modelClassName = NSStringFromClass(model.class);
NSString *modelCellClassIdentifier = [modelClassName stringByAppendingString:@"TableViewCellIdentifier"];
UITableViewCell<ModelUpdatable> *cell = [tableView dequeuReusableCellWithIdentifier:modelCellClassIdentifier];
[cell updateWithModel:model];
因此,如果您的模型名为Person
,则您的单元格标识符为PersonTableViewCellIdentifier
。 (我建议您调用您的手机PersonTableViewCell
。)
我使用这种技术经常使用宏来声明标识符,我将尝试从内存中重现这些标识符,因此将其视为伪代码:
PRODeclareCellIdentifier(model) extern NSString *const model##TableViewCellIdentifier
PRODefineCellIdentifier(model) NSString *const model##TableViewCellIdentifier = @#model##TableViewCellIdentifier
在您的手机标题中,您要说PRODeclareCellIdentifier(Person)
。在实施过程中,您要说PRODefineCellIdentifier(Person)
。我谨慎地使用宏,但它们对于这样的样板来说非常非常有用。