2014-02-17 129 views
9

一段時間以來,我一直在想這個困境。 UITableView中的一個單元本質上是一個視圖,因此UITableViewCell的類應該關注與視圖相關的事物(即表示方法,佈局等),並且它內部沒有任何業務邏輯(通常需要照顧控制器)。但是由於我們沒有每個單元的控制器,只有整個表的控制器,所以我很難找出將我的單元邏輯放在哪裏。將它放入單元格本身會打破MVC,但將它放入表控制器中很難確定從哪個單元格調用方法(如果視圖基於操作,我更願意爲發送者編寫子類,以便我可以添加屬性以幫助我確定這是什麼觀點)。把UITableViewCell邏輯放在哪裏?

例如我有一個單元格,該單元格內有一個UIButton,當按下按鈕時出現UIPopover。現在我在哪裏放置popover演示代碼(演示文稿出現在一個特定的單元格中,因此我必須知道它是從哪個單元中調用的。)

我想知道其他人在這種情況下做什麼以及什麼是他們的最佳實踐。

+2

你可以繼承UITableView和UITableViewCell,然後爲該按鈕添加一個委託方法。例如tableView:buttonWasPressedForCell:&buttonWasPressedForCell :. tableView將符合單元的委託並接收消息buttonWasPressedForCell :.然後,tableView將發送消息tableView:buttonWasPressedForCell:它是委託,在這種情況下,您的控制器。這樣,您就知道哪個UITableView和哪個UITableViewCell消息是從哪個發送的。 – Jonathan

+0

好問題,真棒:) –

回答

3
  1. 如果您將單元格中的彈出窗口的演示文稿,那麼這是最好的選擇。爲什麼?,因爲這不是邏輯,這是視圖相關的事情,因爲使這個動作的按鈕在你的單元格內,那麼代碼應該在你的單元格內(或者你可以發送消息(委託)到你的viewController來顯示)。

  2. 那麼什麼是邏輯?邏輯是例如:計算,日期操作,將事情發送到服務器。所有這些應該在另一個對象中,我們可以稱之爲modulemanager

  3. 控制器可以在所有這些對象之間交換消息(view-model),但視圖和模塊應該相互分離。

更新: 你可能想看看Single Responsibility原則

+0

「邏輯」正在傳遞數據以顯示彈出窗口,併爲單元格子視圖執行回調操作。還必須存在一個解除popover的回調(我們在popover中做了一些事情,並想保存它)。因此,從單元格中呈現彈出窗口,然後用保存彈出窗口中已更改的數據的方法調用tableview控制器,這對我來說似乎是錯誤的。我可能會有偏見。 – carlossless

+1

那麼,最好的方法是創建一個協議,並使tableViewController委託,在按下按鈕之後,將消息傳遞給委託,例如cellButtonWasPressed,並且viewController應該決定要做什麼 –

+0

與@ Jonathan的評論相同。我開始認爲這是一條路。謝謝。 – carlossless

1

通常情況下,這是你的視圖控制器來處理「填充」邏輯爲你的細胞。單元格是您每次填入的收件人。

它在prepareForReuse:UITableViewCell的甚至說:

表視圖的中的tableView委託:的cellForRowAtIndexPath:重用小區時應該始終重置所有內容。

確實,您的單元不應該包含除顯示以外的邏輯。

如果你需要像你的單元格中的按鈕這樣的邏輯,你應該爲你的子類UITableViewCell設置一個委託(你創建一個協議),然後在你的UIViewController中保存單元邏輯。

如果您的單元格是唯一的,我建議您將您的單元格定義爲靜態單元格(無重用標識符)。並建立強有力的聯繫。

0

通常,對於像這樣的任務,我將viewController分配給單元格作爲委託(併爲其定義一些協議)。另外,我一直弱引用對象從中我填充我的手機,所以在按鈕的動作,我會轉發給委託(的viewController)方法是這樣的:

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

所以在這種方式,我知道,從展示我酥料餅的地方,以及哪些信息(適合於sourceItem)顯示在其中。

編輯此外,如果有細胞,避免非常類似的方法重複只需將它添加到功能上面提到的一個參數,並確定所有可能的操作的枚舉多個控件

1

你可以繼承UITableViewUITableViewCell 。然後,爲該按鈕添加委託方法。例如tableView:buttonWasPressedForCell: & buttonWasPressedForCell:。 tableView將符合單元的委託並接收消息buttonWasPressedForCell:。然後,tableView會將消息tableView:buttonWasPressedForCell:發送給它的委託,在這種情況下,您的控制器。通過這種方式,您知道哪些消息是從哪個UITableView發送的,哪些是UITableViewCell

實施例:

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; 
} 
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]; 
} 

當您創建的視圖控制器 你的細胞創建符合MyTableViewCellActionHandler協議的行動處理器,通過動作處理程序View Controller是否需要進行演示。

cell.actionHandler = self.tableViewCellActionHandler; 

您也可以爲您的單元提供數據源並傳入查看模型。(MVVM)這將允許您僅保留單元格中的表示代碼並將所有業務邏輯保留在其所屬的位置。關注點分離。