【问题标题】:How to reference UITableViewController from a UITableViewCell class?如何从 UITableViewCell 类中引用 UITableViewController?
【发布时间】:2014-12-15 13:13:18
【问题描述】:

我有以下几点:

  1. UITableViewController
  2. UITableView
  3. 自定义 UITableViewCell 子类

我为单元格使用了一个 .xib 文件,它是一个 CustomCell 子类。此自定义单元格处理单元格按钮上的某些触摸事件的 IBAction。

我想从单元格中引用 ViewController 及其一些变量。

我应该如何从 UITableViewCell 类访问 UITableViewController?

【问题讨论】:

    标签: ios cocoa-touch uitableview swift uikit


    【解决方案1】:

    我不会在单元格和视图控制器之间创建这种依赖关系 - 这会使架构更加复杂并且单元格不可重用。

    我建议你使用委托模式,这听起来可能有点复杂——尽管你已经在使用(UITableViewDelegate 是一个典型的例子):

    • 使用一种方法didTapCell 创建一个协议MyCellProtocol,接受UITableViewCell 和/或您想要传递给视图控制器的一些自定义数据
    • 在您的自定义单元格中创建一个公共委托属性:weak var cellDelegate: MyCellProtocol?
    • 在单元格的didTapXXX 处理程序或didSelectRowAtIndexPath 中,调用self.cellDelegate?.didTapCell(),传递预期的参数
    • 在您的视图控制器中,实现MyCellProtocol
    • 在视图控制器的cellForRowAtIndexPath 中,当创建/出列单元格时,将其cellDelegate 属性设置为self

    此时,当在您的单元格中完成点击时,将调用视图控制器的didTapCell 方法,您可以从那里执行任何您需要实现的操作。

    关键点是:与其让单元格处理单元格点击/选择,不如通知视图控制器并让它完成工作。

    【讨论】:

    • 上面的第二个项目符号似乎是针对 Objective-C 的。很快就可以这样做:让委托:ClasThatImplementsProtocol
    • 这可能有效。但是当你应该将 dataSource 封装到不同的类时(不要将 DS 放入控制器中),你需要找到连接单元和控制器的不同方式。您可以做的一件事是使用 tableView 委托方法 willDisplayCell 将 tableview 作为委托分配给单元格。然后,您需要在 prepareForReuse 和 dealloc 或 deinit 中取消链接,具体取决于您使用的语言。如果有多个活动的控制器监听同一个通知,通知也不是理想的解决方案。
    • 非常感谢,我知道这是垃圾邮件,但你拯救了我的一天;)祝你好运
    • 如果您在答案中提供一些代码会很棒:) @Antonio
    • 谢谢@Ivan,是的,你是对的,代表应该是weak,刚刚更新了答案。
    【解决方案2】:
    extension UIView {
        var parentViewController: UIViewController? {
            var parentResponder: UIResponder? = self
            while parentResponder != nil {
                parentResponder = parentResponder!.next
                if let viewController = parentResponder as? UIViewController {
                    return viewController
                }
            }
            return nil
        }
    }
    

    在你的牢房里

    if let myViewController = parentViewController as? MyViewController {
        print(myViewController.title)
    }
    

    【讨论】:

    • 我想从嵌套在 uitableviewcell 中的 uicollectionviewcell 执行 segue,这非常有效!谢谢。
    • 在主从项目模板中工作。谢谢。
    • 在 Swift 4 中,.nextResponder() 更改为 .next
    【解决方案3】:

    我认为您不应该这样做,并且可能您做错了什么,但如果您真的需要它,那么只需在您的 CustomCell 类中拥有一个属性。

    weak var viewController : UIViewController
    

    那么当您在cellForRowAtIndexPath 中创建单元格时,设置属性

    cell.viewController = self
    

    之后,您可以轻松地从单元代码中访问视图控制器:

    self.viewController.doSomething()
    

    但是,在我看来,您应该重新设计您的代码。单元不应该关心控制器。它应该只关心显示自己而不关心其他内容

    【讨论】:

    • > "单元格不应该关心控制器。它应该只关心显示自己而不关心其他内容" 这是否意味着如果按钮的操作在自定义单元格中添加按钮也是不好的做法将访问或更改某些模型属性?因为在这种情况下,模型只能从控制器访问,因为它是表视图的源......
    • 当然不是。一个不好的做法是让代码在按钮的动作中处理很多模型的东西。在这种情况下,一个好的做法是在按钮的操作中只包含一行代码。该行应发布通知或调用委托方法。然后控制器应该对这个调用或这个通知做出反应并运行所有需要的代码。控制器,而不是单元格。我希望你明白我在说什么
    • 在大多数 UI 框架中,访问对象的容器非常常见,例如在 ActionScript 中,您可以使用 this.parent 调用父级,从我对 Apple 语言的经验来看,Apple 似乎没有经验使用可视化编程语言就足够了,所以我想这个解决方案是非常容易接受和聪明的,我会给它+1
    • 我认为将 ViewController 定义为单元格内的弱可能会更好。
    • @MuhammedGül 绝对正确。感谢您指出这一点
    【解决方案4】:

    添加扩展

     extension UITableViewCell {
    
            var viewControllerForTableView : UIViewController?{
                return ((self.superview as? UITableView)?.delegate as? UIViewController)
            }
    
        }
    

    现在向下转换如下

       if let viewController = self.viewControllerForTableView as? AnyController{
    
           print(viewController.variable)
    
       } 
    

    【讨论】:

      【解决方案5】:

      最好的方法是实现委托。您的委托将通知视图控制器有关按钮单击的信息。而且,反过来,您的视图控制器(符合上述委托的协议)将处理您要在单击事件上执行的任务。 (委托模式教程可在线获得。如果您想知道如何进行委托,可以查看它们。

      【讨论】:

        【解决方案6】:

        在尝试此之前,请阅读其他 cmets 关于真的想要使用替代方法的信息,但使用此扩展程序将允许您访问 dataSourcedelegate 两者都应该是 UITableViewController

        extension UITableViewCell {
            var tableView:UITableView? {
                get {
                    for var view = self.superview ; view != nil ; view = view!.superview {
                        if view! is UITableView {
                            return (view! as UITableView)
                        }
                    }
                    return nil
                }
            }
        
            var tableViewDataSource:UITableViewDataSource? {
                get {
                    return self.tableView?.dataSource
                }
            }
        
            var tableViewDelegate:UITableViewDelegate? {
                get {
                    return self.tableView?.delegate
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-09
          • 1970-01-01
          • 2013-06-10
          • 1970-01-01
          • 2014-05-02
          • 1970-01-01
          相关资源
          最近更新 更多