将选择器从UITableViewCell类添加到UITableViewController类

时间:2018-10-09 00:26:34

标签: ios swift uitableview

我正在尝试设计自己的UITableViewCell以在AccessoryView中包含一个步进器。因此,我想添加选择器,以便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()
    }
}

2 个答案:

答案 0 :(得分:3)

替代公认的解决方案:

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

//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中,您更改代码以符合委托,并将ViewController设置为委托给单元格

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)")
    }

}

答案 1 :(得分:1)

实际上,问题在于addTarget(_ target, ...)方法调用target上的选择器。即使您像使用完整路径一样指定它。

您可以尝试将目标设置为nil,如果文档正确,它应该可以工作:

  

目标对象,即,其操作方法被调用的对象。如果指定nil,则UIKit会在响应者链中搜索一个对象,该对象响应指定的操作消息并将该消息传递给该对象。

如果这没有帮助,则完全指定目标即可解决该问题。您只需要将引用传递给控制器​​即可。