使用委托和协议将数据从一个 Custom TableView Cell 传递到另一个
Passing data from one Custom TableView Cell to another using delegates and protocols
我正在努力思考 swift 中的委托和协议,特别是如何在自定义 tableview 单元格之间传递数据。
我已经建立了一个简单的项目来测试它,其中包含三个 类、一个 TableViewController 和两个使用 .xib 布局的自定义单元格:DateLabelCell 和 DatePickerCell。期望的结果是,当更改日期选择器时,它会使用新值更新日期标签单元格。
目前 DatePicker Cell 正在与 TableViewController 通信,但我似乎无法让 TableViewController 然后与 Datelabel Cell 通信。我认为这与 Datelabel Cell 没有正确引用 tableviewcontroller 有关?
非常感谢任何帮助或见解。
干杯,
TableViewController
import UIKit
protocol DateLabelDelegate: AnyObject {
func setDateLabel(_ text: String)
}
class TableViewController: UITableViewController {
weak var dateLabelDelegate: DateLabelDelegate?
override func viewDidLoad() {
super.viewDidLoad()
tableViewSetup()
}
func tableViewSetup() {
// Format tableView
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200
tableView.tableFooterView = UIView(frame: CGRect.zero) // Removes Empty Cells
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
// Register Cells
tableView.register(UINib(nibName: "DatePickerCell", bundle: nil), forCellReuseIdentifier: "DatePickerCell")
tableView.register(UINib(nibName: "DateLabelCell", bundle: nil), forCellReuseIdentifier: "DateLabelCell")
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DateLabelCell", for: indexPath) as! DateLabelCell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell", for: indexPath) as! DatePickerCell
cell.dateDelegate = self
return cell
}
}
}
extension TableViewController: DatePickerDelegate {
func setDate(_ text: String) {
print("WORKING: TableViewController: DatePickerDelegate")
dateLabelDelegate?.setDateLabel(text)
}
}
DatePickerCell
import UIKit
protocol DatePickerDelegate: AnyObject {
func setDate(_ text: String)
}
class DatePickerCell: UITableViewCell {
weak var dateDelegate: DatePickerDelegate?
@IBOutlet var datePicker: UIDatePicker!
let formatter = DateFormatter()
override func awakeFromNib() {
super.awakeFromNib()
formatter.dateFormat = "dd.MM.yyyy"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
}
@IBAction func datePickerDidChange(_ sender: Any) {
let result = formatter.string(from: datePicker.date)
print("RESULT -> \(result)")
dateDelegate?.setDate(result)
}
}
DateLabelCell
import UIKit
class DateLabelCell: UITableViewCell {
@IBOutlet var dateLabel: UILabel!
let date = Date()
let formatter = DateFormatter()
let sendingTableVC = TableViewController()
override func awakeFromNib() {
super.awakeFromNib()
sendingTableVC.dateLabelDelegate = self
formatter.dateFormat = "dd.MM.yyyy"
let result = formatter.string(from: date)
dateLabel.text = "Date: \(result)"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension DateLabelCell: DateLabelDelegate {
func setDateLabel(_ text: String) {
print("DATE LABEL UPDATED")
dateLabel.text = text
}
}
更新 tableview/collectionviewcell 的正确方法是重新加载特定的单元格。并且您应该始终维护代表您的 table 视图单元格的数据,因为您的单元格不是持久的和可重复使用的。您可以在创建单元格时使用该数据填充单元格的属性。
在您的情况下,日期是需要保留的数据。在这种情况下,您可以简单地将其作为控制器中的一个字段。
import UIKit
class DateLabelCell: UITableViewCell {
@IBOutlet var dateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
func setDate(_ text: String) {
dateLabel.text = text
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
class TableViewController: UITableViewController {
var date: String = "Date"
.......
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DateLabelCell", for: indexPath) as! DateLabelCell
cell.setDate(self.date)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell", for: indexPath) as! DatePickerCell
cell.dateDelegate = self
return cell
}
}
}
extension TableViewController: DatePickerDelegate {
func setDate(_ text: String) {
self.date = text
tableView.reloadRows(at: [IndexPath(item: 0, section: 0)], with: .automatic)
}
}
您还可以使用回调,它非常强大并且更容易理解:
class TableViewController: UITableViewController {
//MARK: Properties
var date = "today"
.....
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DateLabelCell", for: indexPath) as! DateLabelCell
cell.setDate(self.date)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell", for: indexPath) as! DatePickerCell
cell.dateSelectedCallback = { newDate in //here we get the new date
self.date = newDate
self.tableView.reloadData()
}
return cell
}
}
}
DateLabelCell
class DateLabelCell: UITableViewCell {
//MARK: IBOutlets
@IBOutlet var dateLabel: UILabel!
//MARK: Cell setup
func setDate(_ text: String) {
dateLabel.text = text
}
}
DatePickerCell
这里我们创建了一个可选的回调变量。为什么可选?如果它没有被实施,它就不会崩溃。回调就像简单的完成处理程序,您可以通过它们传递任何数据。
class DatePickerCell: UITableViewCell {
//MARK: IBOutlets
@IBOutlet var datePicker: UIDatePicker!
//MARK: Properties
var dateSelectedCallback: ((_ date: String) -> ())?
let formatter = DateFormatter()
//MARK: Lifecycles
override func awakeFromNib() {
super.awakeFromNib()
formatter.dateFormat = "dd.MM.yyyy"
}
//MARK: IBActions
@IBAction func datePickerDidChange(_ sender: Any) {
let result = formatter.string(from: datePicker.date)
print("RESULT -> \(result)")
dateSelectedCallback?(result) //we pass the date string here
}
}
我正在努力思考 swift 中的委托和协议,特别是如何在自定义 tableview 单元格之间传递数据。
我已经建立了一个简单的项目来测试它,其中包含三个 类、一个 TableViewController 和两个使用 .xib 布局的自定义单元格:DateLabelCell 和 DatePickerCell。期望的结果是,当更改日期选择器时,它会使用新值更新日期标签单元格。
目前 DatePicker Cell 正在与 TableViewController 通信,但我似乎无法让 TableViewController 然后与 Datelabel Cell 通信。我认为这与 Datelabel Cell 没有正确引用 tableviewcontroller 有关?
非常感谢任何帮助或见解。
干杯,
TableViewController
import UIKit
protocol DateLabelDelegate: AnyObject {
func setDateLabel(_ text: String)
}
class TableViewController: UITableViewController {
weak var dateLabelDelegate: DateLabelDelegate?
override func viewDidLoad() {
super.viewDidLoad()
tableViewSetup()
}
func tableViewSetup() {
// Format tableView
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 200
tableView.tableFooterView = UIView(frame: CGRect.zero) // Removes Empty Cells
tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
// Register Cells
tableView.register(UINib(nibName: "DatePickerCell", bundle: nil), forCellReuseIdentifier: "DatePickerCell")
tableView.register(UINib(nibName: "DateLabelCell", bundle: nil), forCellReuseIdentifier: "DateLabelCell")
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 2
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DateLabelCell", for: indexPath) as! DateLabelCell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell", for: indexPath) as! DatePickerCell
cell.dateDelegate = self
return cell
}
}
}
extension TableViewController: DatePickerDelegate {
func setDate(_ text: String) {
print("WORKING: TableViewController: DatePickerDelegate")
dateLabelDelegate?.setDateLabel(text)
}
}
DatePickerCell
import UIKit
protocol DatePickerDelegate: AnyObject {
func setDate(_ text: String)
}
class DatePickerCell: UITableViewCell {
weak var dateDelegate: DatePickerDelegate?
@IBOutlet var datePicker: UIDatePicker!
let formatter = DateFormatter()
override func awakeFromNib() {
super.awakeFromNib()
formatter.dateFormat = "dd.MM.yyyy"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func prepareForReuse() {
}
@IBAction func datePickerDidChange(_ sender: Any) {
let result = formatter.string(from: datePicker.date)
print("RESULT -> \(result)")
dateDelegate?.setDate(result)
}
}
DateLabelCell
import UIKit
class DateLabelCell: UITableViewCell {
@IBOutlet var dateLabel: UILabel!
let date = Date()
let formatter = DateFormatter()
let sendingTableVC = TableViewController()
override func awakeFromNib() {
super.awakeFromNib()
sendingTableVC.dateLabelDelegate = self
formatter.dateFormat = "dd.MM.yyyy"
let result = formatter.string(from: date)
dateLabel.text = "Date: \(result)"
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
extension DateLabelCell: DateLabelDelegate {
func setDateLabel(_ text: String) {
print("DATE LABEL UPDATED")
dateLabel.text = text
}
}
更新 tableview/collectionviewcell 的正确方法是重新加载特定的单元格。并且您应该始终维护代表您的 table 视图单元格的数据,因为您的单元格不是持久的和可重复使用的。您可以在创建单元格时使用该数据填充单元格的属性。
在您的情况下,日期是需要保留的数据。在这种情况下,您可以简单地将其作为控制器中的一个字段。
import UIKit
class DateLabelCell: UITableViewCell {
@IBOutlet var dateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
func setDate(_ text: String) {
dateLabel.text = text
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
class TableViewController: UITableViewController {
var date: String = "Date"
.......
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DateLabelCell", for: indexPath) as! DateLabelCell
cell.setDate(self.date)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell", for: indexPath) as! DatePickerCell
cell.dateDelegate = self
return cell
}
}
}
extension TableViewController: DatePickerDelegate {
func setDate(_ text: String) {
self.date = text
tableView.reloadRows(at: [IndexPath(item: 0, section: 0)], with: .automatic)
}
}
您还可以使用回调,它非常强大并且更容易理解:
class TableViewController: UITableViewController {
//MARK: Properties
var date = "today"
.....
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "DateLabelCell", for: indexPath) as! DateLabelCell
cell.setDate(self.date)
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell", for: indexPath) as! DatePickerCell
cell.dateSelectedCallback = { newDate in //here we get the new date
self.date = newDate
self.tableView.reloadData()
}
return cell
}
}
}
DateLabelCell
class DateLabelCell: UITableViewCell {
//MARK: IBOutlets
@IBOutlet var dateLabel: UILabel!
//MARK: Cell setup
func setDate(_ text: String) {
dateLabel.text = text
}
}
DatePickerCell
这里我们创建了一个可选的回调变量。为什么可选?如果它没有被实施,它就不会崩溃。回调就像简单的完成处理程序,您可以通过它们传递任何数据。
class DatePickerCell: UITableViewCell {
//MARK: IBOutlets
@IBOutlet var datePicker: UIDatePicker!
//MARK: Properties
var dateSelectedCallback: ((_ date: String) -> ())?
let formatter = DateFormatter()
//MARK: Lifecycles
override func awakeFromNib() {
super.awakeFromNib()
formatter.dateFormat = "dd.MM.yyyy"
}
//MARK: IBActions
@IBAction func datePickerDidChange(_ sender: Any) {
let result = formatter.string(from: datePicker.date)
print("RESULT -> \(result)")
dateSelectedCallback?(result) //we pass the date string here
}
}