Я создал класс, который будет создавать / управлять несколькими кнопками и метками и добавлять их в представление, но я не могу получить действия от кнопок для запуска.
Вот простая версия кода без 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.





Проблема в том, что, поскольку вы не сохраняете 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.
Это сработает, но не уверен, что это отличное решение (см. Мой обновленный ответ)
Интересная находка, я заметил, что если у вас был такой же селектор в ViewController, он вызывается для кода в вопросе. @AshleyMills, не могли бы вы объяснить, почему это происходит?
Ох .. Целевой объект, то есть объект, метод действия которого вызывается. Если вы укажете nil, UIKit ищет в цепочке респондентов объект, который отвечает на указанное сообщение действия, и доставляет сообщение этому объекту. Охкк ... понял: |
Спасибо! Это лучший способ сделать то, что я хочу?
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) }