ios - 将 UITableViewCell 类中的选择器添加到 UITableViewController 类

标签 ios swift uitableview

我正在尝试设计我自己的 UITableViewCell,以便在 AccessoryView 中包含一个 Stepper。因此,我想添加选择器,以便 ViewController 能够处理被更改的值的行为。 (UITableViewCell 应该只负责在其标签中显示结果)

目前,我可以通过对 UITableViewCell 类使用 addTarget 来修改标签的文本,但是当我将目标添加到 UITableViewController 类时,出现以下错误:

2018-10-08 20:04:39.157912-0400 MyProject[1003:45273] -[MyProject expansionSelectionValueDidChange:]: unrecognized selector sent to instance 0x7fa88700fc00
2018-10-08 20:04:39.167219-0400 MyProject[1003:45273] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MyProject.PlayerSelectionCell expansionSelectionValueDidChange:]: unrecognized selector sent to instance 0x7fa88700fc00'

我正在使用 X-Code 10 和 Swift 4 开发 iOS 12 应用程序。

这是 UITableViewCell 的代码:

class PlayerSelectionCell: UITableViewCell {

    @objc func stepperValueDidChange(_ sender: UIStepper) {
        textLabel?.text = "\(newValue) Players"
    }

    override func awakeFromNib() {
        let stepper = UIStepper()
        stepper.addTarget(self, action: #selector(stepperValueDidChange(_:)), for: .valueChanged)
        stepper.addTarget(self, action: #selector(SetupViewController.expansionSelectionValueDidChange(_:)), for: .valueChanged)
        self.accessoryView = stepper
    }
}

这是我的 UITableViewController 的代码

class SetupViewController: UITableViewController {

    @IBOutlet var setupTableView: UITableView!

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0:
            return "Expansions"
        case 1:
            return "Players"
        default:
            return nil
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch section {
        case 0:
            return Expansions.allCases.count
        case 1:
            return 3
        default:
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Expansion Selection", for: indexPath) as? ExpansionCell ?? ExpansionCell()
            cell.textLabel?.text = Expansions.allCases[indexPath.row].rawValue
            return cell
        } else if indexPath.section == 1 && indexPath.row == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Player Selection", for: indexPath) as? PlayerSelectionCell ?? PlayerSelectionCell()
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Player Detail", for: indexPath) as? PlayerCell ?? PlayerCell()
            cell.textLabel?.text = "Player \(indexPath.row)"
            return cell
        }
    }

    @objc func playerCountValueDidChange(_ sender: UIStepper) {
        print("Value : \(sender.value)")
    }

    @objc func expansionSelectionValueDidChange(_ sender: UISwitch) {
        print("Value : \(sender.isOn)")
    }

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

最佳答案

替代公认的解决方案:

根据情况,您可以尝试使用委托(delegate)代替操作/目标

//Declare a delegate for the cell
protocol PlayerSelectionCellDelegate : class {
    func playerSelectionCell(_ cell:PlayerSelectionCell, didChangeValue:Double)
    func playerSelectionCell(_ cell:PlayerSelectionCell, expansionSelectionValueDidChange:Bool)
}

class PlayerSelectionCell: UITableViewCell {

    weak var delegate : PlayerSelectionCellDelegate?        //Set a weak var to allocate the delegate

    @objc func stepperValueDidChange(_ sender: UIStepper) {
        delegate?.playerSelectionCell(self, didChangeValue: sender.value)
    }

    @objc func expansionSelectionValueDidChange(_ sender: UISwitch) {
        delegate?.playerSelectionCell(self, expansionSelectionValueDidChange: sender.isOn)
    }

    override func awakeFromNib() {
        let stepper = UIStepper()
        stepper.addTarget(self, action: #selector(stepperValueDidChange), for: .valueChanged)

        //This line should be reference to the UISwitch Action
        selectionSwitch.addTarget(self, action: #selector(expansionSelectionValueDidChange), for: .valueChanged)
        self.accessoryView = stepper
    }
}

在 ViewController 中,您更改代码以符合委托(delegate)并将 ViewController 设置为委托(delegate)给单元格

class SetupViewController: UITableViewController {

    @IBOutlet var setupTableView: UITableView!

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch section {
        case 0:
            return "Expansions"
        case 1:
            return "Players"
        default:
            return nil
        }
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch section {
        case 0:
            return Expansions.allCases.count
        case 1:
            return 3
        default:
            return 0
        }
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Expansion Selection", for: indexPath) as? ExpansionCell ?? ExpansionCell()
            cell.textLabel?.text = Expansions.allCases[indexPath.row].rawValue
            return cell
        } else if indexPath.section == 1 && indexPath.row == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Player Selection", for: indexPath) as? PlayerSelectionCell ?? PlayerSelectionCell()
            cell.delegate = self            //Set the ViewController to be delegated by cell
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "Player Detail", for: indexPath) as? PlayerCell ?? PlayerCell()
            cell.textLabel?.text = "Player \(indexPath.row)"
            return cell
        }
    }

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

    //Remove the actions and implements the delegate methods
    func playerSelectionCell(_ cell: PlayerSelectionCell, didChangeValue players: Double) {
        print("Value Players: \(players)")
    }

    func playerSelectionCell(_ cell: PlayerSelectionCell, expansionSelectionValueDidChange selected: Bool) {
        print("Value Selected: \(selected)")
    }

}

关于ios - 将 UITableViewCell 类中的选择器添加到 UITableViewController 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52711733/

相关文章:

ios - 在 UITableViewController 中覆盖数据源和委托(delegate)方法时是否需要调用 super?

objective-c - 在 UITableViews 和 View 之间导航并保留数据?

ios - native : InAppBrowser is not installed or you are running on a browser. 回退到 window.open。在 iOS 上

iOS SQLite.swift,关于应用升级?

ios - 一个 Storyboard,两个 Controller

swift - 从 UIWebView 创建 PDF

ios - 是否可以使用 UIImageView 组合/分层图像并仍然保持其透明度?

ios - 如何使用 RxSwift 观察 UITextField 中的文本变化?

ios - 如何在 Swift 3 中使用 AVAudioPlayer 播放 .ogg 音频文件?

uitableview - 使用 Storyboard的快速动态表格 View 单元格高度