Как написать селектор, который принимает аргумент в Swift 3

В Swift 2 это работало (я умышленно не рассматривал методы просмотра таблицы)...

 import Foundation
 import UIKit

 private extension Selector {
    static let didTapButton = #selector(TableVC.buttonTapped(_ :))

 }

 class TableVC: UITableViewController{

     override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
         let btnAccView:UIButton = UIButton(frame: CGRectMake(0, 0, 27, 27))
         btnAccView.addTarget(self, action: .didTapButton, forControlEvents: UIControlEvents.TouchUpInside)
         btnAccView.tag = indexPath.row
     }


     func buttonTapped(sender: UIButton){
         print("button tapped at row \(sender.tag)")
     }

 }

В Swift 3 это вызывает ошибку: "TableVC не имеет кнопки-члена".

Мне просто нужно написать селектор, который принимает аргумент. Я пытался возиться с синтаксисом во всех отношениях, о которых я могу думать, но ничего не сработало. Спасибо за вашу помощь

+2
источник поделиться
3 ответа

Прежде всего, вам нужно изменить buttonTapped чтобы первая метка аргумента была подавлена. Вставьте знак подчеркивания перед меткой внутреннего аргумента, чтобы он выглядел следующим образом:

func buttonTapped(_ sender: UIButton) {

Раньше его сигнатурой метода был TableVC.buttonTapped(sender:), и теперь его подпись будет TableVC.buttonTapped(_:). Возможно, вам придется удалить пробел между подчеркиванием и двоеточием в вашем расширении, но после этого он должен работать.

Как примечание, есть ли какая-то конкретная причина, по которой вы используете расширение на Selector? Эта модель расширения наиболее полезна обычно с такими вещами, как имена уведомлений, которые могут быть легко опечатаны, что приводит к сложным ошибкам. Поскольку компилятор Swift автоматически проверяет объявления #selector независимо от того, где они размещены, вы можете просто поместить его прямо в свой код - не требуется расширение.

+3
источник

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

class TableVC: UIViewController {
    func buttonTapped(sender: UIButton) { /*...*/ }
}

Вы можете ссылаться на него извне класса TableVC как:

  • #selector(TableVC.buttonTapped(sender:))
  • #selector(TableVC.buttonTapped)

Второй работает, потому что в buttonTapped есть только одна функция TableVC, поэтому компилятору не нужна полная подпись, чтобы устранить ее.

Из кода внутри TableVC вы можете упростить его шаг дальше и просто использовать #selector(buttonTapped), потому что в этот момент вы находитесь в области класса и можете безопасно вывести метод класса.

(#selector(TableVC.buttonTapped(_:)) которую вы используете, работает только в том случае, если ваш метод объявлен как func buttonTapped(_ sender: UIButton). В вашем случае использования не имеет значения, имеет ли параметр sender метка аргумента или нет - вы просто должны быть последовательны в этом между вашим объявлением func и вашим выражением #selector.)

И, как отмечает @Bob, нет необходимости в расширении Selector, потому что компилятор уже проверяет селектор.

+1
источник

Используйте следующий способ реализации селектора для действия кнопки:

import UIKit
class MyViewController: UIViewController {
    let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))

    override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        let action = #selector(MyViewController.tappedButton)
        myButton.addTarget(self, action: action, forControlEvents: .touchUpInside)
    }

    func tappedButton(sender: UIButton?) {
        print("tapped button")
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}
0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос