【问题标题】:How to get a UITableViewCell from one of its subviews如何从其子视图之一获取 UITableViewCell
【发布时间】:2013-07-19 10:20:18
【问题描述】:

我在每个UITableViewCells 中都有一个UITableView 和一个UITextField。我的 ViewController 中有一个方法,它处理每个单元格的文本字段的“退出时结束”事件,我想要做的是用新文本更新我的模型数据。

我目前拥有的是:

- (IBAction)itemFinishedEditing:(id)sender {
    [sender resignFirstResponder];

    UITextField *field = sender;
    UITableViewCell *cell = (UITableViewCell *) field.superview.superview.superview;

    NSIndexPath *indexPath = [_tableView indexPathForCell:cell];

    _list.items[indexPath.row] = field.text;
}

当然,field.superview.superview.superview 是可行的,但它看起来很老套。有没有更优雅的方式?如果我将UITextField 的标签设置为cellForRowAtIndexPath 中的单元格的indexPath.row,即使在插入和删除行之后,该标签是否总是正确的?

对于那些密切关注的人,您可能会认为我的.superview 太多了,对于iOS6,您是对的。但是,在 iOS7 中,单元格的内容视图和单元格本身之间的层次结构中有一个额外的视图(NDA 阻止我详细说明)。这准确地说明了为什么做 superview 的事情有点 hacky,因为它取决于知道UITableViewCell 是如何实现的,并且可能会随着操作系统的更新而中断。

【问题讨论】:

    标签: ios uitableview


    【解决方案1】:

    一种更好的方法是遍历视图层次结构,使用class 方法检查每个父视图是否为UITableViewCell。这样,您就不会受到 UITextField 和单元格之间的超级视图数量的限制。

    类似的东西:

    UIView *view = field;
    while (view && ![view isKindOfClass:[UITableViewCell class]]){ 
        view = view.superview;
    }
    

    【讨论】:

    • 真的很棒,很棒!非常感谢,你为我节省了很多时间。只是不要忘记稍后将“view”转换为“UITableViewCell *”,它就像一个魅力,并且非常紧凑。 (但为什么我没有自己想到呢?;-))
    【解决方案2】:

    由于您的目标实际上是获取文本字段的索引路径,您可以这样做:

    - (IBAction)itemFinishedEditing:(UITextField *)field {
        [field resignFirstResponder];
    
        CGPoint pointInTable = [field convertPoint:field.bounds.origin toView:_tableView];    
    
        NSIndexPath *indexPath = [_tableView indexPathForRowAtPoint:pointInTable];
    
        _list.items[indexPath.row] = field.text;
    }
    

    【讨论】:

    • 不错!我非常喜欢这个。
    • 我将此标记为正确答案,因为正如您所说,它巧妙地解决了我的真正目标(不需要获取表格视图单元格)。但是,我已经尝试将文本字段的标记设置为 indexPath.row 并且效果很好,这也是我最终将使用的。
    • 请记住,仅当您的表格行无法添加、删除或重新排序时,为索引路径使用标签才有效。
    • 示例 - 如果您在屏幕上至少一些可见行上方的索引路径中插入一行,则插入点下方的可见行不会更新,并且仍将具有旧标签。这假设您不打电话给reloadData,只打电话给insertRowsAtIndexPaths:。如果您只是将可见单元格从屏幕的一个部分重新排序到可见屏幕的另一部分,以便没有单元格进入或离开屏幕,则根本不会调用 cellForRowAtIndexPath:。同样,这假设您没有调用reloadData
    • @maddy btw, self.bounds.origin 在您的示例代码中应该是 field.bounds.origin。我试图编辑你的答案,但我不会让我做这么小的改变。
    【解决方案3】:

    基本上在这种情况下,我希望您将 IBAction 方法放入单元格而不是视图控制器中。然后当一个动作被触发时,一个单元格发送一个委托给一个视图控制器实例。

    这是一个例子:

    @protocol MyCellDelegate;
    
    
    @interface MyCell : UITableViewCell
    
    @property (nonatomic, weak) id<MyCellDelegate> delegate;
    
    @end
    
    @protocol MyCellDelegate <NSObject>
    
    - (void)tableViewCell:(MyCell *)cell textFieldDidFinishEditingWithText:(NSString *)text;
    
    @end
    

    在一个单元的实现中:

    - (IBAction)itemFinishedEditing:(UITextField *)sender
    {
        // You may check respondToSelector first
        [self.delegate tableViewCell:self textFieldDidFinishEditingWithText:sender.text];
    }
    

    所以现在单元格将通过委托方法传递自身和文本。

    假设视图控制器已将单元格的委托设置为自身。现在视图控制器将实现一个委托方法。

    在视图控制器的实现中:

    - (void)tableViewCell:(MyCell *)cell textFieldDidFinishEditingWithText:(NSString *)text
    {
        NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
        _list.items[indexPath.row] = text;
    }
    

    无论 Apple 如何更改表格视图单元格的视图层次结构,这种方法也都有效。

    【讨论】:

    • 我认为这可能违反了 MVC 原则。还有人这么认为吗?
    • @JacobRelkin 我同意。它赋予单元一个属于控制器的职责。
    • 这种方法(为您的 UITableViewCell 创建自定义委托协议)正是 Ray Wenderlich tutorial 中建议的用于制作“清晰”风格的待办事项列表应用程序(搜索 SHCTableViewCellDelegate 以获取到右侧部分)。我不确定它是否会破坏 MVC。单元只是通知控制器发生了某些事情,因此由控制器执行它认为合适的操作(例如,更改模型)。
    【解决方案4】:

    您可以将UITableViewCell 本身作为弱关联附加到UITextField,然后在UITextFieldDelegate 方法中将其取出。

    const char kTableViewCellAssociatedObjectKey;
    

    在你的 UITableViewCell 子类中:

    - (void)awakeFromNib {
        [super awakeFromNib];
        objc_setAssociatedObject(textField, &kTableViewCellAssociatedObjectKey, OBJC_ASSOCIATION_ASSIGN);
    }
    

    在你的 UITextFieldDelegate 方法中:

    UITableViewCell *cell = objc_getAssociatedObject(textField, &kTableViewCellAssociatedObjectKey);
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    //...
    

    我还建议每次从 UITableView 出列单元格时重新关联,以确保文本字段与正确的单元格相关联。

    【讨论】:

    • +1 因为我以前从未听说过 objc_setAssociatedObject()!
    猜你喜欢
    • 1970-01-01
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-23
    • 1970-01-01
    相关资源
    最近更新 更多