Добавьте селектор из класса UITableViewCell в класс UITableViewController - PullRequest
0 голосов
/ 09 октября 2018

Я пытаюсь создать свой собственный UITableViewCell для включения Stepper в AccessoryView.Поэтому я хотел бы добавить селектор, чтобы ViewController обрабатывал поведение изменяемого значения.(UITableViewCell должен отвечать только за отображение результата в его метке)

В настоящее время я могу изменить текст метки, используя addTarget для класса UITableViewCell, но когда я добавляю цель в класс 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 голосов
/ 09 октября 2018

В качестве альтернативы принятому решению:

В зависимости от случая вы можете попробовать использовать делегат вместо action / target

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

}
0 голосов
/ 09 октября 2018

На самом деле проблема в том, что метод addTarget(_ target, ...) вызывает селектор на target.Даже если вы укажете его так же, как вы указали полный путь.

Можно попробовать установить целевое значение на nil, и оно будет работать, если документация верна:

Целевой объект, то есть объект, метод действия которого вызывается.Если вы укажете nil, UIKit ищет в цепочке респондента объект, который отвечает на указанное сообщение действия, и доставляет сообщение этому объекту.

И если это не помогает, указание цели точно должнореши это.Вам просто нужно будет передать ссылку на контроллер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...