UIButton implements block callbacks and handles multiple UIControlEvents events

Tip: This article is mainly to solve most of the existing methods on the network, can only save a UIControlEvents event restrictions. Today, suddenly trying to add block callbacks to UIButton’s response was a little hard…… Checked online, did not find a solution that can solve the problem perfectly. So, with this article. It should be noted that this article is a violent implementation. If there is a method to realize the orthodox, hope reader generous with your criticism.

target

UIButton’s most commonly used response method is the method that inherits from UIControl:

- - (void) addTarget: (nullable, ID), target, action: (SEL), action, forControlEvents: (UIControlEvents), controlEvents;

That’s how it works:

[button addTarget:self action:@selector (actionOne:) forControlEvents:UIControlEventTouchUpInside]; [button addTarget:self action:@selector (actionTwo:) forControlEvents:UIControlEventTouchUpOutside]; [self.view addSubview:button]; - (void) actionOne: (UIButton * button) {NSLog (@ actionOne);} - (void) actionTwo: (UIButton * button) {NSLog (@ actionTwo);}

The effect you want to achieve is:

[button addBlockAction:^{NSLog (@ blockOne);} forControlEvents:UIControlEventTouchUpInside] [button addBlockAction:^{; NSLog (@ blockTwo);} forControlEvents:UIControlEventTouchUpOutside];

If your project only uses the UIControlEventTouchUpInside event, my advice doesn’t have to go on. The existing data on the Internet is enough, but you should pay more attention to it when you use it. Most of the code on the Internet can only save the last added UIControlEvents event.

Again, this article is a violent implementation and is not recommended if there is no need to avoid it.

thinking

When dealing with multiple UIControlEvents, each UIControlEvents is associated with the corresponding block and can be read accurately, which is the difficult point to implement. Now that you’ve seen it, it shows that you’ve tried and noticed the problem.

Here I introduce my ideas: the use of method name transfer
, the specific way is:

  1. Dynamic generation of SEL containing UIControlEvents flags but without real methods.
  2. Override the method of invoking the response method to parse UIControlEvents from the received SEL and pass it to the response method via the performSelector:withObject: method.

Here is the code, where inheritance is used:

.h file

#import < UIKit/UIKit.h> typedef void (^BlockAction) (); @interface BlockButton: UIButton - (void) addBlockAction: (BlockAction) blockAction forControlEvents: (UIControlEvents) controlEvents; @end

.m file

#import "BlockButton.h" static NSString *suffix = "_block_button"; @interface @ BlockButton (UIControlEvents) / storage and the corresponding block @property (nonatomic, strong) NSMutableDictionary< NSNumber BlockAction> *blocks; * @ end @implementation BlockButton (NSMutableDictionary< NSNumber BlockAction> * *, blocks) {if {_blocks = (_blocks!) [[NSMutableDictionary alloc] init] return _blocks;};} - (void) addBlockAction: (BlockAction) blockAction forControlEvents: (UIControlEvents) controlEvents [self.blocks setObject:blockAction forKey:@ {/ / storage (controlEvents); / / UIControlEvents and ensure the uniqueness of the symbol generation method. SEL sel = NSSelectorFromString ("[NSString stringWithFormat:@%@%@", @ (controlEvents), suffix]); [self addTarget:self action:sel forControlEvents:controlEvents];} / / rewriting method call response - (void) sendAction: (SEL) action to: (ID) target forEvent: (UIEvent * event) {NSString *actionString = NSStringFromSelector (action if ([actionString); hasSuffix:suffix]) {/ / parse and transfer `UIControlEvents` NSNumber @ *events = (actionString.integerValue) [self (doAction:); performSelector:@selector withObject:events];} else {if ([super respondsToSelector:@selector (sendAction:to:forEvent:)] [super sendAction:action to:target forEvent:event]) {}};} - (void) doAction: (NSNumber * events) {/ / block corresponding to remove the dictionary, execute BlockAction block objectForKey: = [self.blocks events]; if (block) {block}} (@end);

End

Passing arguments using method names…… I’m hopeless, too. And this is the amazing way to happen to have sendAction:to:forEvent:, students, please don’t study.

Students who have other ideas can come to exchange and communicate with each other.

Obviously six months did not start, and writing the article is still so time-consuming, curious oh.