I've created a class that will create/manage several buttons and labels, and add them to a view, but I can't get the actions from the buttons to trigger.
Here's a simple version of the code without a 'MakerClass' that works fine (code is in the main 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)
}
And here is a version where I put the creation of the button into a different Class
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)
}
}
The project I've been using to play around with this can be downloaded from here
I may be going about this the wrong way, as I am new to iOS programming
The problem is that as you're not retaining MakerClass
, the target for the button is set to NSNull()
You can see this by adding…
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>
If you want the button to fire an action method in your view controller, you could do…
class MakerClass {
init(intoView: UIView, with viewController: ViewController) {
// configure
backgroundButton.addTarget(viewController, action: #selector(iwastouched(_:)), for: .touchUpInside)
}
}
But that ties your MakerClass
to that specific ViewController
class.
Instead, your MakerClass
could return the formatted button and then set the target/action in the view controller.
Update
Per @RakeshaShastri's comment below, as the target is set to NSNull()
, the app will go up the responder chain looking for an UIResponder
(generally a UIView
or UIViewController
) with the correct func signature. The responder chain in your case is…
backgroundButton
-> ViewController.view
-> ViewController
-> UIWindow
You can test this out by also adding
@objc func iwastouched(_ sender: UIButton!) {
print("touched")
}
to your ViewController
class.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.