UITableViewCell如何与其UITableView进行通信?

8
我正在创建一个自定义网格视图,这意味着我正在创建一个与UITableView有很多共同之处的类。其中我想做好的一件事是单元格与网格视图之间的通信。
因此,我想知道表视图单元格如何与其表视图通讯。例如,单元格如何通知表视图它的删除按钮已被点击,并需要从表视图中移除?
有几种可能的方案,但我不确定苹果公司使用的是哪种方案,因为UITableView或UITableViewCell的头文件没有揭示这一点(或者我漏看了什么)。
最终目标是让单元格和网格视图进行私有通信,也就是说,不公开任何公共方法或协议(如果可能的话)。

1
KKGridView(在GitHub上:https://github.com/kolinkrewinkel/KKGridView)是一个经典的实现,与UITableView有许多相似之处,并且具有一组复杂的内部方法,您可以从中获得灵感。 - viggio24
AQGridView(http://github.com/AlanQuatermain/AQGridView)也是基于UITableView结构的一种实现。但据我所知,两个对象之间不可能保持私有通信(我可能错了!)。 - JP Illanes
5个回答

1

现在删除按钮可能是一个不好的例子,因为iOS有一个内置的方法,允许您删除行并通知您的数据源,该方法称为:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath

然而,为了理解,如果您想在表视图单元格中添加一个按钮,并执行不在标准iOS库中的操作,则可以在单元格中创建一个委托,并将您的tableview的数据源文件设置为委托。

基本上,您可以像这样子类化UITableViewCell

MyCustomCell.h

@protocol MyCustomCellDelegate;
@interface MyCustomCell : UITableViewCell
@property (nonatomic, unsafe_unretained) id <MyCustomCellDelegate> delegate; //Holds a reference to our tableView class so we can call to it. 
@property (nonatomic, retain) NSIndexPath *indexPath; //Holds the indexPath of the cell so we know what cell had their delete button pressed
@end

/* Every class that has <MyCustomCellDelegate> in their .h must have these methods in them */
@protocol MyCustomCellDelegate <NSObject>
- (void)didTapDeleteButton:(MyCustomCell *)cell;
@end

MyCustomCell.m

@synthesize delegate = _delegate;
@synthesize indexPath = _indexPath;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) 
    {
    /* Create a button and make it call to a method in THIS class called deleteButtonTapped */
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame = CGRectMake(5, 5, 25, 25);
    [button addTarget:self action:@selector(deleteButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

    }
    return self;
}

/**
 * This is the method that is called when the button is clicked.
 * All it does is call to the delegate. (Whatever class we assigned to the 'delegate' property)
 */
- (void)deleteButtonTapped:(id)sender
{
    [self.delegate didTapDeleteButton:self];
}

您的TableView数据源应该长这样。

MyDataSource.h

/* We conform to the delegate. Which basically means "Hey you know those methods that we defined in that @protocol I've got them and you can safely call to them" */
@interface MyDataSource : UIViewController <MyCustomCellDelegate, UITableViewDelegate, UITableViewDataSource>
 @property (nonatomic,retain) NSArray *tableData;//We will pretend this is the table data
 @property (nonatomic,retain) UITableView *tableView;// We will pretend this is the tableview

@end

MyDataSource.m

//We will pretend we synthesized and initialized the properties
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier: @"MyCustomCell"];
    if (!cell) 
        cell = [[DownloadQueueCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: @"MyCustomCell"];
    cell.delegate = self;      // Make sure we set the cell delegate property to this file so that it calls to this file when the button is pressed.
    cell.indexPath = indexPath;// Set the indexPath for later use so we know what row had it's button pressed.
    return cell;
}


- (void)didTapDeleteButton:(MyCustomCell *)cell;
{

   // From here we would likely call to the apple API to Delete a row cleanly and animated
   // However, since this example is ignoring the fact that they exist
   // We will remove the object from the tableData array and reload the data
   [self.tableData removeObjectAtIndexPath:cell.indexPath];
   [self.tableView reloadData];

}

基本上,长话短说。对于您的网格视图,您只需创建一个委托方法,告诉用户某个按钮被按下了。

0

UITableViewCell 项是 UITableView 的子视图。因此,您可以使用它来在单元格和 tableView 之间进行通信。反过来,UITableView 具有委托和数据源与其控制器进行通信。这可能会有所帮助。


谢谢你的回答。从UITableViewCell到UITableView的引用并不是实际的问题。我的问题涉及单元格和表视图之间的通信,以及如何保持该通信私有。 - Bart Jacobs
我的观点是控制器应该决定如何处理按钮的点击。因此,它可以是 [[(UITableView *)self.superview delegate] performSelector:@selector(someButtonPressedInCell:) withObject:self] - voromax

0

我不确定是否需要一个私人通信渠道。

表视图通过调整表视图单元格的大小并在空白处创建一个新视图,使删除视图与给定单元格相邻。

强制执行的删除视图是使用表视图、索引路径和表视图委托实例化的。删除视图处理触摸并向表视图委托发送消息,包括表视图和索引路径。表视图委托完成从数据源中删除条目的工作,动画地移除单元格并刷新表视图。刷新后,表视图根据数据源重新绘制所有可见单元格。


0

您可以让自定义的单元格 UIView 拥有一个类型为您的网格视图的私有属性。当您将这些单元格添加到您的网格视图中时,更新该属性以指向网格视图。

我有自己的自定义网格视图,并且是通过这种方式实现的。

另一种方法是在您的网格视图中拥有一个处理单元格并返回其索引的方法,UITableView 也有这些方法。这样,当用户按下单元格中的按钮时,您只需要获取该单元格并将其传递给网格视图,获取该单元格的索引,然后使用该索引来访问数据...


0

您可以使用类别

您可以在单独的类别中声明私有方法,并将其放置在单独的文件中。在想要使用这些私有方法的类的实现文件中,您需要导入带有私有类别的此文件,并使用私有方法。因此,使用它们的类的公共.h文件保持不变。

例如:

MyGridViewCell.h:

@interface MyGridViewCell : UIView
// ...
@end

MyGridViewCell.m:

@implementation MyGridViewCell : UIView
// ...
@end

现在是私有方法类别接口:

MyGridViewCellPrivate.h:

@interface MyGridViewCell (Private)

- (void) privateMethod1;

@end

实现:

MyGridViewCellPrivate.m:

@implementation MyGridViewCell (Private)

- (void) privateMethod1
{
    // ...
}

@end

标题与之前相同:

MyGridView.h:

@interface MyGridView : UIView

- (void) publicMethod1;

@end

但实现可能会使用私有 API:

MyGridView.m:

#import "MyGridViewCell.h"
#import "MyGridViewCellPrivate.h"

- (void) publicMethod1
{
    // Use privateMethod1
}

你能详细解释一下这个方法吗? - Bart Jacobs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接