【发布时间】:2018-01-13 09:04:43
【问题描述】:
虽然使用 UITableView 有两种类型的方法,即 数据源和委托仍然应该连接到同一个父视图控制器类。
有没有办法在不同的类中定义委托和数据源?
为什么我们需要将委托和数据源分开?
注意:这个问题适用于 UICollectionView 和类似的对象
【问题讨论】:
-
一言以蔽之,YES。
标签: ios objective-c swift uitableview delegates
虽然使用 UITableView 有两种类型的方法,即 数据源和委托仍然应该连接到同一个父视图控制器类。
有没有办法在不同的类中定义委托和数据源?
为什么我们需要将委托和数据源分开?
注意:这个问题适用于 UICollectionView 和类似的对象
【问题讨论】:
标签: ios objective-c swift uitableview delegates
正如其他响应中关于委托模式的充分解释,我们可以将 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
}
}
【讨论】:
是的,您可以将它们放在单独的类中。它们通常在同一个类中,因为您可能需要在 didSelectRowAtIndexPath 中的委托方法中使用数据(如数组):
Tableview 和 Collectionview 数据源和委托基于Delegate design pattern,您可以在其中将一些工作委托给其他对象。
为什么需要两种不同的协议?
因为数据源用于提供控制 tableview/collectionview 状态的数据,而委托提供行为并控制如何使用数据。
【讨论】:
在一些特殊情况下,我会使用两个不同的类来实现delegate和dataSource方法。
例如:
在我的项目中,一些数据包含在一个实例中(我们称之为全局用户 ),比如用户的文章、用户的评论、用户的产品……
我为全局用户创建了一个实例类。在这堂课中,当用户登录成功时,我有一些NSMutableArray 用于用户数据。
我从我的数据服务器请求他的数据并存储在这些数据数组中。
之后,当用户想要查看他的产品时,他会点击my product之类的按钮,然后推送到MyProductListVC,在MyProductListVC,我有一个tableView init 来展示他的产品,但我不想再次从我的数据服务器请求他的产品数据,因为我的全球用户类中有他的所有产品数据,所以我将tableView's dataSource 设置为全球用户类,并制作delegate 到 MyProductListVC,这个逻辑在我的项目上运行了很长时间。这就是我在不同类中定义委托和数据源的方式。
关于你的第二个问题:
Why we need seperation as delegates and datasources?
我根据我的项目回答了这个问题,首先,我希望所有用户的数据都集中在一个类上,这样我就可以方便地管理用户的数据。其次,当我需要更改视图中数据的显示方式时,我只需要更改MyProductListVC 中的代码即可。
以下是我认为最重要的:
我可以将所有请求方法放在我的全局用户类中,我不希望在我的MyProductListVC 和任何其他 VC 中有太多请求代码,因为在我的项目中,VC 只需要显示数据,不要需要申请。
【讨论】:
NSObject 类
委托是子类化的“替代品”。它采用适用于您的应用情况的通用行为。
数据源只是提供要显示的数据。
显然有可能出现这样的情况,即两个视图具有相同的行为,但显示的数据不同。在这种情况下,为两个视图和两个不同的数据源设置一个委托是很方便的(而不是在每个数据源方法的开头都使用ifs)。这意味着至少有一个视图有一个不是其委托的数据源。
举个例子:你有一个表格视图来显示球队的球员。有一些额外的行为。你为此写了一个委托。然后你有一个窗口,其中有两个视图,一个是主队的,一个是客队的。
两个视图具有相同的行为适应委托和不同的数据源来为玩家提供。
【讨论】: