How to add UIViewController as target of UIButton action created in programmatically created UIView?
If you are adding the button programmatically to a subclass of UIView, then you can do it one of two ways:
You can make the button a property of the view, and then in the viewController that instantiates the view you can set the target of the button as follows:
[viewSubclass.buttonName addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
This will set the button's target to a method of buttonTapped: in the viewController.m
You can create a protocol in your subview, which the parent viewController will conform to. In your view, when you add your button set it to call a method in your view. Then call the delegate method from that view so that your viewController can respond to it:
In the top your view subclass .h create the protocol:
@protocol ButtonProtocolName
- (void)buttonWasPressed;
@end
Create a property for the delegate:
@property (nonatomic, assign) id <ButtonProtocolName> delegate;
In the subclass .m set your button selector:
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
In the buttonTapped: method call the delegate method:
- (void)buttonTapped:(id)sender {
[self.delegate buttonWasPressed];
}
In your viewController.h you'll need to make sure it conforms to the protocol:
@interface someViewController : UIViewController <SomeButtonProtocolName>
In your viewController.m when you init your subview, you'll have to set the delegate:
SomeView *view = ... // Init your view
// Set the delegate
view.delegate = self;
Finally, add the delegate method buttonWasPressed to the viewController.m:
- (void)buttonWasPressed {
// Put code here for button's intended action.
}
Updated to provide Swift example
// Simple delegate protocol.
protocol SomeViewDelegate: class {
// Method used to tell the delegate that the button was pressed in the subview.
// You can add parameters here as you like.
func buttonWasPressed()
}
class SomeView: UIView {
// Define the view's delegate.
weak var delegate: SomeViewDelegate?
// Assuming you already have a button.
var button: UIButton!
// Once your view & button has been initialized, configure the button's target.
func configureButton() {
// Set your target
self.button.addTarget(self, action: #selector(someButtonPressed(_:)), for: .touchUpInside)
}
@objc func someButtonPressed(_ sender: UIButton) {
delegate?.buttonWasPressed()
}
}
// Conform to the delegate protocol
class SomeViewController: UIViewController, SomeViewDelegate {
var someView: SomeView!
func buttonWasPressed() {
// UIViewController can handle SomeView's button press.
}
}
Additionally, here is a quick example using a closure instead of a delegate. (This can approach also be implemented in ObjC using blocks.)
// Use typeAlias to define closure
typealias ButtonPressedHandler = () -> Void
class SomeView: UIView {
// Define the view's delegate.
var pressedHandler: ButtonPressedHandler?
// Assuming you already have a button.
var button: UIButton!
// Once your view & button has been initialized, configure the button's target.
func configureButton() {
// Set your target
self.button.addTarget(self, action: #selector(someButtonPressed(_:)), for: .touchUpInside)
}
@objc func someButtonPressed(_ sender: UIButton) {
pressedHandler?()
}
}
class SomeViewController: UIViewController {
var someView: SomeView!
// Set the closure in the ViewController
func configureButtonHandling() {
someView.pressedHandler = {
// UIViewController can handle SomeView's button press.
}
}
}