Различное поведение между addTarget и addGestureRecognizer

У меня есть функция, которая создает кнопку с функцией выбора в качестве цели. Адрес кнопки передается handleSelectPhoto,

lazy var image1Button = createButton(selector: #selector(handleSelectPhoto))
func createButton(selector: Selector) -> UIButton {
    let button = UIButton(type: .system)
    button.addTarget(self, action: selector, for: .touchUpInside)
    return button
}
@objc func handleSelectPhoto(button: UIButton) {
    // Do something with button, this works
}

Теперь я пытаюсь изменить класс выше с UIButton на UIImageView, как показано ниже,

lazy var image1Button = createButton(selector: #selector(handleSelectPhoto))
func createButton(selector: Selector) -> UIImageView {
    let view = UIImageView()
    view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: selector))
    view.isUserInteractionEnabled = true
    return view
}
@objc func handleSelectPhoto(button: UIImageView) {
    // HERE, button does not get passed
}

С учетом вышеуказанных изменений в handleSelectPhoto, экземпляр кнопки неверен. Я не могу прочитать его как тип UIImageView.

Если я добавлю функцию выбора с помощью addGestureRecognizer, он ведет себя иначе, чем добавление функции выбора с помощью addTargetс точки зрения того, как функция выбора выполняется с параметрами? Может быть, я не понимаю, как работает эта функция выбора...

2 ответа

Решение

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

lazy var image1Button = createButton(selector: #selector(handleSelectPhoto:))

UIKit автоматически поймет, что параметр методов селектора будет иметь тип UITapGestureRecognizer, Теперь перепишите нижеприведенный метод, как этот, и вам будет хорошо.

@objc func handleSelectPhoto(gesture: UITapGestureRecognizer) {
        if let buttonImageView = gesture.view as? UIImageView {
            //Here you can make changes in imageview what ever you want.
        }
}

Добавление цели к чему-то вроде UIGestureRecognizer или же UIButton передает только один параметр выбранной функции. Этот параметр зависит от типа, к которому вы собираетесь добавить цель.

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

Во втором сценарии вы добавляете цель к UITapGestureRecognizerтаким образом, переданный экземпляр будет именно этим распознавателем жестов, который не может быть типа UIImageView,

Таким образом, разница с точки зрения целевого параметра между UIGestureRecognizer а также UIButton нет разницы Они оба передают свои экземпляры выбранной функции.

От UIView Перспектива подкласса есть разница, что UIGestureRecognizer не подкласс UIView, но UIButton является. Вот почему вы можете просто использовать пройденный UIButton экземпляр в вашем первом фрагменте. Во втором фрагменте вам нужно использовать свойство view UIGestureRecognizer,

guard let imageView = gestureRecognizer.view as? UIImageView else { return }

Помимо вашего реального вопроса, кажется, важно уточнить, как писать #selectorправильно. Вы уже делаете это правильно. Никаких изменений не требуется. Некоторые могут сказать, что вам нужно добавить (_:) или же : к вашему селектору вот так: #selector(handleSelectPhoto(_:)) но это не правда В общем случае эти специальные символы нужно добавлять только при выборе метода, у которого есть метод перегрузки с другим количеством параметров, но с тем же базовым именем.

Другие вопросы по тегам