Программное действие UIButton не вызывается

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

Вот простая версия кода без MakerClass, которая отлично работает (код находится в основном ViewController):

@objc func pressed(_ sender: UIButton!) {
    print("pressed")
}
    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    let backgroundButton = UIButton()
    backgroundButton.backgroundColor = UIColor.green
    backgroundButton.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
    self.view.addSubview(backgroundButton)

    backgroundButton.addTarget(self, action: #selector(pressed(_:)), for: .touchUpInside)

}

А вот версия, в которой я поместил создание кнопки в другой класс.

ViewController

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    MakerClass(intoView: self.view)                
}

MakerClass

class MakerClass {


    var backgroundButton: UIButton = UIButton()


    @objc func iwastouched(_ sender: UIButton!) {
        print("touched")
    }

    init(intoView: UIView){

        backgroundButton.backgroundColor = UIColor.red
        backgroundButton.frame = CGRect(x: 0, y: 200, width: 100, height: 100)
        intoView.addSubview(backgroundButton)
        backgroundButton.addTarget(self, action: #selector(iwastouched(_:)), for: .touchUpInside)

    }


}

Проект, который я использовал, чтобы поиграть с этим, можно скачать с здесь

Возможно, я ошибаюсь, так как я новичок в программировании на iOS.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
147
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что, поскольку вы не сохраняете MakerClass, цель для кнопки установлена ​​на NSNull().

Вы можете увидеть это, добавив…

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    let buttons = view.subviews as! [UIButton]
    for button in buttons {

        print(button)
        print("Target :", button.allTargets.first!)
    }
}
<UIButton: 0x7ff89fd04110; frame = (0 0; 100 100); opaque = NO; layer = <CALayer: 0x60000257bac0>>
Target : <TestProgrammaticButton.ViewController: 0x7ff89ff08050>
<UIButton: 0x7ff89fd05020; frame = (0 200; 100 100); opaque = NO; layer = <CALayer: 0x60000257bb40>>
Target : <null>

Если вы хотите, чтобы кнопка запускала метод действия в вашем контроллере представления, вы можете сделать…

class MakerClass {
    init(intoView: UIView, with viewController: ViewController) {
        // configure
        backgroundButton.addTarget(viewController, action: #selector(iwastouched(_:)), for: .touchUpInside)
    }
}

Но это связывает ваш MakerClass с этим конкретным классом ViewController.

Вместо этого ваш MakerClass может вернуть отформатированную кнопку, а затем установить цель / действие в контроллере представления.


Обновлять

Согласно приведенному ниже комментарию @ RakeshaShastri, поскольку для цели задано значение NSNull(), приложение будет подниматься по цепочке респондентов в поисках UIResponder (обычно UIView или UIViewController) с правильной сигнатурой func. Цепочка респондентов в вашем случае…

backgroundButton -> ViewController.view -> ViewController -> UIWindow

Вы можете проверить это, также добавив

@objc func iwastouched(_ sender: UIButton!) {
    print("touched")
}

в ваш класс ViewController.

Спасибо! Это лучший способ сделать то, что я хочу? init(intoView: UIView, withVC: ViewController){ backgroundButton.backgroundColor = UIColor.red backgroundButton.frame = CGRect(x: 0, y: 200, width: 100, height: 100) intoView.addSubview(backgroundButton) backgroundButton.addTarget(withVC, action: #selector(ViewController.pressed(_:)), for: .touchUpInside) }

Dominic Williams 24.08.2018 12:16

Это сработает, но не уверен, что это отличное решение (см. Мой обновленный ответ)

Ashley Mills 24.08.2018 12:23

Интересная находка, я заметил, что если у вас был такой же селектор в ViewController, он вызывается для кода в вопросе. @AshleyMills, не могли бы вы объяснить, почему это происходит?

Rakesha Shastri 24.08.2018 12:32

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

Rakesha Shastri 24.08.2018 12:41

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