【问题标题】:Delegate and Datasource in different classes possible? - UITableView不同类中的委托和数据源可能吗? - UITableView
【发布时间】:2018-01-13 09:04:43
【问题描述】:

虽然使用 UITableView 有两种类型的方法,即 数据源和委托仍然应该连接到同一个父视图控制器类

有没有办法在不同的类中定义委托和数据源?

为什么我们需要将委托和数据源分开?

注意:这个问题适用于 UICollectionView 和类似的对象

【问题讨论】:

  • 一言以蔽之,YES。

标签: ios objective-c swift uitableview delegates


【解决方案1】:

正如其他响应中关于委托模式的充分解释,我们可以将 tableview Datasource 和 Delegate 声明为不同的对象,以避免大规模 ViewControllers 并实现精益 ViewControllers。

这是一个使用委托设计模式的代码示例。

import UIKit

// MARK: Cell

class ItemCell: UITableViewCell{
    var label: UILabel!
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 20))
        label.textColor = .black
        label.backgroundColor = .yellow
        contentView.addSubview(label)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: Main View Controller

class BlueViewController: UIViewController{

    var tableView: UITableView!
    var myDataSourse: MyTVDataSource!
    var myDelegate: MyTVDelegate!


    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .blue
        tableView = UITableView()
        myDataSourse = MyTVDataSource(tableView: tableView)
        myDelegate = MyTVDelegate()
        myDelegate.presentingController = self
        tableView.dataSource = myDataSourse
        tableView.delegate = myDelegate
        tableView.register(ItemCell.self, forCellReuseIdentifier: "Cell")

        self.view.addSubview(tableView)



        self.tableView.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0)
            ])
    }
}
extension BlueViewController: BluePresenting{
    func currentSelected(_ indexPath: IndexPath) {
        print(indexPath)
    }


}

// MARK: TableViewDelegate


protocol BluePresenting: class {
    func currentSelected(_ indexPath: IndexPath)
}

class MyTVDelegate: NSObject,UITableViewDelegate{

   var presentingController: BluePresenting?

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            presentingController?.currentSelected(indexPath)
    }
}

// MARK: TableView DataSource


class MyTVDataSource: NSObject, UITableViewDataSource{
    private var tableView: UITableView
    private var items = ["Item 1","item 2","item 3","Item 4"]

    init(tableView: UITableView) {
        self.tableView = tableView
    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count

    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = ItemCell(style: .default, reuseIdentifier: "Cell")
        cell.label.text = items[indexPath.row]

        return cell
    }

}

【讨论】:

    【解决方案2】:

    是的,您可以将它们放在单独的类中。它们通常在同一个类中,因为您可能需要在 didSelectRowAtIndexPath 中的委托方法中使用数据(如数组):

    Tableview 和 Collectionview 数据源和委托基于Delegate design pattern,您可以在其中将一些工作委托给其他对象。

    为什么需要两种不同的协议?

    因为数据源用于提供控制 tableview/collectionview 状态的数据,而委托提供行为并控制如何使用数据。

    【讨论】:

    • 这怎么可能,因为我的 tableview 只包含在 viewcontroller 中。我想使用哪些类?
    • 您的 tableview 在视图控制器内部,它公开了两个委托属性(不同的协议),您可以在其中传递任何符合这些协议的类(对象)。
    • @Saranjith:已编辑答案。我希望我能理解你的问题并回答它。
    • @Saranjith:更常见的是,您在一个完全不同的类中定义数据源,该类与 tableview 无关,但只专注于提供数据。
    • @Saranjith :如果您想在 uitableview 子类中定义数据源,您当然可以这样做,但理想情况下您希望将视图和数据类分开。使用委托的全部意义在于分离职责。
    【解决方案3】:

    在一些特殊情况下,我会使用两个不同的类来实现delegatedataSource方法。

    例如:

    在我的项目中,一些数据包含在一个实例中(我们称之为全局用户 ),比如用户的文章、用户的评论、用户的产品……

    我为全局用户创建了一个实例类。在这堂课中,当用户登录成功时,我有一些NSMutableArray 用于用户数据。 我从我的数据服务器请求他的数据并存储在这些数据数组中。

    之后,当用户想要查看他的产品时,他会点击my product之类的按钮,然后推送到MyProductListVC,在MyProductListVC,我有一个tableView init 来展示他的产品,但我不想再次从我的数据服务器请求他的产品数据,因为我的全球用户类中有他的所有产品数据,所以我将tableView's dataSource 设置为全球用户类,并制作delegateMyProductListVC,这个逻辑在我的项目上运行了很长时间。这就是我在不同类中定义委托和数据源的方式。

    关于你的第二个问题:

    Why we need seperation as delegates and datasources?

    我根据我的项目回答了这个问题,首先,我希望所有用户的数据都集中在一个类上,这样我就可以方便地管理用户的数据。其次,当我需要更改视图中数据的显示方式时,我只需要更改MyProductListVC 中的代码即可。

    以下是我认为最重要的:

    我可以将所有请求方法放在我的全局用户类中,我不希望在我的MyProductListVC 和任何其他 VC 中有太多请求代码,因为在我的项目中,VC 只需要显示数据,不要需要申请。

    【讨论】:

    • 你的全局类的基类是什么?
    • NSObject
    • 你可以在uitableview类中定义数据源,但我不会这样做,因为我不认为将请求数据方法放入uitableview类是一个好主意。
    • 我的全局类是单实例,所以当我使用它时,它已经初始化完成,如果你想使用uitableview作为数据源,你必须确保你使用时的uitableview已经初始化完成。否则,您将收到警告或错误。
    【解决方案4】:

    委托是子类化的“替代品”。它采用适用于您的应用情况的通用行为。

    数据源只是提供要显示的数据。

    显然有可能出现这样的情况,即两个视图具有相同的行为,但显示的数据不同。在这种情况下,为两个视图和两个不同的数据源设置一个委托是很方便的(而不是在每个数据源方法的开头都使用ifs)。这意味着至少有一个视图有一个不是其委托的数据源。

    举个例子:你有一个表格视图来显示球队的球员。有一些额外的行为。你为此写了一个委托。然后你有一个窗口,其中有两个视图,一个是主队的,一个是客队的。

    两个视图具有相同的行为适应委托和不同的数据源来为玩家提供。

    【讨论】:

      猜你喜欢
      • 2014-09-22
      • 2012-07-01
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 2015-11-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多