如何在 UITableViewController 的两个并排实例之间传递数据

How to Pass Data Between Two Side-by-Side Instances of a UITableViewController

在界面生成器中,我在 UIStackView 的容器视图中嵌入了两个 UITableViewController 实例。两个 TableViewControllers 都链接到相同的自定义 class 文档(请参见下面的代码)。它们之间的唯一区别在于它们显示的数据。两者都有允许多项选择的 UITableViews——但我也希望在一个 table 中选择任何内容会导致取消选择另一个 table 中的所有内容,反之亦然。我尝试使用委托进行设置,但我不知道如何在 UITableViewController 中从另一个实例引用一个实例,以将每个实例分配为另一个实例。

除了子 class 名称之外,我找不到任何关于委托或通过任何其他方式引用视图控制器的相关信息。因此,在我最近的尝试中,我尝试引用父对象的另一个子对象。相关代码如下:

protocol TableViewSelectionDelegate: AnyObject {
    func didSelectInTableView(_ tableView: UITableView)
}

class TableViewController: UITableViewController, TableViewSelectionDelegate {

    weak var delegate: TableViewSelectionDelegate?

    @IBOutlet var numbersTableView: UITableView!
    @IBOutlet var lettersTableView: UITableView!

    // Received by segue
    var displayables: [Character] = []

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // (It's too soon to determine parents/children in viewDidLoad())
    override func viewWillAppear(_ animated: Bool) {

        guard let tableViewControllers = parent?.children else {
            print("No tableViewControllers found!")
            return
        }

        switch restorationIdentifier {

        case "NumbersTableViewController":
            for tableViewController in tableViewControllers {
                if tableViewController.restorationIdentifier == "LettersTableViewController" {
                    delegate = tableViewController as? TableViewSelectionDelegate
                }
            }

        case "LettersTableViewController":
            for tableViewController in tableViewControllers {
                if tableViewController.restorationIdentifier == "NumbersTableViewController" {
                    delegate = tableViewController as? TableViewSelectionDelegate
                }
            }

        default: print("Unidentified Table View Controller")
        }
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        delegate?.didSelectInTableView(tableView)
    }

    func didSelectInTableView(_ tableView: UITableView) {

        switch tableView {

        case numbersTableView:
            numbersTableView.indexPathsForSelectedRows?.forEach { indexPath in
                numbersTableView.deselectRow(at: indexPath, animated: false)
            }

        case lettersTableView:
            lettersTableView.indexPathsForSelectedRows?.forEach { indexPath in
                lettersTableView.deselectRow(at: indexPath, animated: false)
            }

        default: print("Unidentified Table View")
        }
    }
}

运行 以上内容并点击 table 中的任何一个都会导致 "Unidentified Table View" 打印到控制台,并且 table 的选择都不会通过在中进行选择来清除另一个。

任何关于如何获得我想要的结果的见解都将不胜感激。如果这里有什么不清楚的地方,请告诉我,我会进行更新。

通过委托在 UITableViewController 的两个实例之间传递信息显然并不像最初看起来那么复杂。唯一值得注意的部分是委托的设置。在自定义 TableViewController class 中,当一个实例被初始化时,它需要将自己设置为另一个实例的委托。就是这样!

在这种情况下,要从另一个实例中引用一个实例,可以使用 tableViewController 的父级访问另一个子 tableViewController。虽然可能有更好的方法来执行此操作,但请参阅我的特定解决方案的代码。值得注意的是,由于父 属性 尚未在 viewDidLoad() 之后设置,我需要在 viewWillAppear() 中进行设置。另请注意,此方法不需要使用 restorationIdentifiers 或标签。相反,它通过它的 tableView 属性.

间接确定了 tableViewController 实例

委托的didSelectInTableView()函数传递了在另一个tableViewController实例中选择的selectedInTableView。由于委托需要清除自己选择的行,因此不需要 selectedInTableView。也就是说,对于仅清除行,该函数不需要传递任何内容。

protocol TableViewSelectionDelegate: AnyObject {
    func didSelectInTableView(_ selectedInTableView: UITableView)
}

class TableViewController: UITableViewController, TableViewSelectionDelegate {

    weak var delegate: TableViewSelectionDelegate?

    // Received by segue
    var displayables: [Character] = []

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    // (It's too soon to determine parents/children in viewDidLoad())
    override func viewWillAppear(_ animated: Bool) {

        guard let siblingTableViewControllers = parent?.children as? [TableViewController] else { return }

        switch tableView {

        case siblingTableViewControllers[0].tableView: siblingTableViewControllers[1].delegate = self
        case siblingTableViewControllers[1].tableView: siblingTableViewControllers[0].delegate = self

        default: print("Unidentified Table View Controller")
        }
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        delegate?.didSelectInTableView(tableView)
    }

    func didSelectInTableView(_ selectedInTableView: UITableView) {

        // selectedTableView is NOT the one that needs to be cleared
        // The function only makes it available for other purposes

        tableView.indexPathsForSelectedRows?.forEach { indexPath in
            tableView.deselectRow(at: indexPath, animated: false)
        }
    }
}

请随时纠正我的概念和术语。