在哪里放UITableViewCell逻辑?

时间:2014-02-17 14:58:48

标签: ios objective-c ipad uitableview

有一段时间我脑子里已经陷入了这种困境。 UITableView中的单元格本质上是一个视图,因此UITableViewCell的类应该处理与视图相关的事物(即表示方法,布局等),并且内部没有业务逻辑(通常需要处理控制器)。但是由于我们没有每个单元的控制器而只有整个表的控制器,所以我很难弄清楚在哪里放置我的单元逻辑。将它放在单元格本身会破坏MVC,但是将它放在表控制器中会使得很难确定调用该方法的单元格(如果视图是基于动作的,我更喜欢为我的发送者编写子类,所以我可以添加属性来帮助我确定这是什么观点)。

例如我有一个单元格,该单元格内部有一个UIButton,当按下按钮时会出现UIPopover。现在我在哪里放置popover演示代码(演示文稿出现在一个特定的单元格中,因此我必须知道从哪个单元格调用它。)

我想知道其他人在这种情况下做了什么以及他们的最佳做法是什么。

5 个答案:

答案 0 :(得分:3)

  1. 如果你把popover的演示文稿放在单元格中,那么它是最好的选择。为什么?,因为这不是逻辑,这是视图相关的事情,因为执行此操作的按钮位于您的单元格内,然后代码应该在您的单元格内(或者您可以将消息(委托)发送到您的viewController以显示)。

  2. 然后是什么逻辑?逻辑是例如:计算,日期操作,向服务器发送内容。所有这些都应该在我们可以称之为modulemanager的另一个对象中。

  3. 控制器可以在所有这些对象(view - model)之间交换消息,但视图和模块应该相互分离。

  4. 更新: 您可能需要查看Single Responsibility原则

答案 1 :(得分:1)

通常情况下,View Controller会为您的单元格处理“填充”逻辑。单元格是您每次填写的收件人。

甚至在prepareForReuse:的{​​{1}}中说:

  

tableView中的表视图委托:cellForRowAtIndexPath:应该在重用单元格时重置所有内容。

事实上,除了显示之外,你的单元格不应该包含任何逻辑。

如果您需要单元格中的逻辑按钮,则应该为您的子类UITableViewCell设置一个委托(您创建一个协议),然后在UIViewController中保存单元格逻辑。

如果您的单元格是唯一的,我建议您将单元格定义为静态单元格(无重用标识符)。并与之建立强有力的联系。

答案 2 :(得分:1)

您可以继承UITableViewUITableViewCell。然后,为按钮添加委托方法。例如tableView:buttonWasPressedForCell:& buttonWasPressedForCell:。 tableView将符合单元格的委托并接收消息buttonWasPressedForCell:。然后,tableView会将消息tableView:buttonWasPressedForCell:发送给它的委托,在本例中是您的控制器。通过这种方式,您可以了解发送邮件的UITableViewUITableViewCell

示例:

<强> ABCTableView.h

@protocol ABCTableViewDelegate <NSObject, UITableViewDelegate>

// You may not need this delegate method in a different UIViewController.
// So, lets set it to optional.
@optional

// Instead of passing the cell you could pass the index path.
- (void)tableView:(ABCTableView *)tableView buttonWasPressedForCell:(ABCTableViewCell *)cell;

@end


@interface ABCTableView : UITableView

// Declare the delegate as an IBOutlet to enable use with IB.
@property (weak, nonatomic) IBOutlet id<ABCTableViewDelegate> delegate;

@end

<强> ABCTableView.m

@implementation ABCTableView

@dynamic delegate;


- (void)buttonWasPressedForCell:(ABCTableViewCell *)cell
{
    // Check if the delegate responds to the selector since
    // the method is optional.
    if ([self.delegate respondsToSelector:@selector(tableView:buttonWasPressedForCell:)])
    {
        [self.delegate tableView:self buttonWasPressedForCell:cell];
    }
}

@end

<强> ABCTableViewCell.h

@protocol ABCTableViewCellDelegate;


@interface ABCTableViewCell : UITableViewCell

// Declare the delegate as an IBOutlet to enable use with IB.
@property (weak, nonatomic) IBOutlet id<ABCTableViewCellDelegate> delegate;

@end


@protocol ABCTableViewCellDelegate <NSObject>

// You may not need this delegate method in a different custom UITableView.
// So, lets set it to optional.
@optional

- (void)buttonWasPressedForCell:(ABCTableViewCell *)cell;

@end

<强> ABCTableViewCell.m

@implementation ABCTableViewCell

- (IBAction)action:(id)sender
{
    // Check if the delegate responds to the selector since
    // the method is optional.
    if ([self.delegate respondsToSelector:@selector(buttonWasPressedForCell:)])
    {
        [self.delegate buttonWasPressedForCell:self];
    }
}

@end

注意: 当您在tableView:cellForRowAtIndexPath:中出列单元格或使用Interface Builder添加单元格时,请确保将单元格的委托设置为tableView。

E.g。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ABCTableViewCell *cell = (ABCTableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"Cell"];

    cell.delegate = tableView;

    return cell;
}

答案 3 :(得分:0)

通常对于像这样的任务,我将viewController作为委托分配给单元格(并为其定义一些协议)。另外,我保持对我填充单元格的对象的弱引用,所以在按钮的操作中,我将转发到委托(viewController)方法,如下所示:

- (void)actionOnCell:(UITableViewCell *)cell fromView:(UIView *)sender withItem:(id)sourceItem;

所以通过这种方式,我知道从哪里显示我的popover,以及哪些信息(适用于sourceItem)显示在其中。

编辑此外,如果单元格上有多个控件以避免重复相似的方法,您可以在上面提到的函数中添加一个参数,并定义所有可能操作的枚举

答案 4 :(得分:0)

为单元格创建操作处理程序和数据源。让您的数据源符合数据源协议(View Model)。然后,细胞甚至不需要知道数据模型。

在界面中:TableViewCell

@property (nonatomic, weak) id <SomeTableViewCellActionHandler> actionHandler;

@protocol SomeTableViewCellActionHandler <NSObject>
- (void)cell:(SomeTableViewCell *)cell didReceiveStartButtonAction:(UIButton *)button;
- (void)cell:(SomeTableViewCell *)cell didReceivePauseButtonAction:(UIButton *)button;
- (void)cell:(SomeTableViewCell *)cell didReceiveClearButtonAction:(UIButton *)button;
@end

实施

- (void)prepareActionsForControls
{
    [self.startButton addTarget:self action:@selector(handleStartButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.pauseButton addTarget:self action:@selector(handlePauseButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.clearButton addTarget:self action:@selector(handleClearButtonAction:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)handleStartButtonAction:(id)sender
{
    [self.actionHandler cell:self didReceiveStartButtonAction:sender];
}

- (void)handlePauseButtonAction:(id)sender
{
    [self.actionHandler cell:self didReceivePauseButtonAction:sender];
}

- (void)handleClearButtonAction:(id)sender
{
    [self.actionHandler cell:self didReceiveClearButtonAction:sender];
}

在View Controller中创建单元格时 创建一个符合MyTableViewCellActionHandler协议的动作处理程序,如果需要进行演示,则将动作处理程序传递给View Controller。

cell.actionHandler = self.tableViewCellActionHandler;

您还可以为您的单元格提供数据源并传入视图模型。 (MVVM)这将允许您仅在单元​​格中保留演示文稿代码,并将所有业务逻辑保留在其所属的位置。关注点分离。