I'm trying to dismiss the presented view controller by doing it from the button directly, instead of making a seperate method just for it, but I'm lost on how to get this to work, or if it's even possible.
Any help offered is appreciated!
Code I'm trying:
[dismissButton addTarget:self action:@selector(dismissViewControllerAnimated:YES completion:NULL) forControlEvents:UIControlEventTouchUpInside];
What I'm NOT wanting to do:
- (void)dismissThis
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
It won't work like that. From the documentation of UIControl
s addTarget:action:forControlEvents:
:
The action message may optionally include the sender and the event as parameters, in that order.
So you have three possible selectors:
@selector(name)
@selector(nameWithParam:)
@selector(nameWithParam: otherParam:)
if your selector is @selector(dismissViewControllerAnimated:completion:)
it will be called with the sender instead of the animated BOOL and the event instead of the completion handler block which will crash you app.
edit to clarify why it crashes:
dismissViewControllerAnimated:completion:
copies the completion block by sending the copy
message. The event object doesn't implement copy
and you will get an NSInvalidArgumentException
.
Apple's standard API doesn't support it, but it's easy to add this functionality through a category on UIControl. JTTargetActionBlock adds this functionality. It's also available as a Cocoapod.
[button addEventHandler:^(UIButton *sender, UIEvent *event) {
[self dismissViewControllerAnimated:YES completion:nil];
} forControlEvent:UIControlEventTouchUpInside];
The way I like to handle this is to subclass UIButton
and add a block-based action:
@interface BlockButton : UIButton
@property (nonatomic, copy) void (^onPress)();
@end
@implementation BlockButton
-(id) initWithFrame:(CGRect)frame
{
if(self = [super initWithFrame:frame]) {
[self addTarget:self
action:@selector(pressed:)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void) pressed:(id)sender
{
if(self.onPress)self.onPress();
}
@end
Then instead of
[dismissButton addTarget:self action:@selector(dismissViewControllerAnimated:YES completion:NULL) forControlEvents:UIControlEventTouchUpInside];
- (void)dismissThis
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
you can use:
dismissButton.onPress = ^{
[self dismissViewControllerAnimated:YES completion:NULL];
};
I'm sure you could adapt this slightly to use a UIButton
category instead, if you really don't want a custom button class.