// // UIControl+runTimeProtect.m // ThePaperBase // // Created by scar1900 on 15/10/26. // Copyright © 2015年 scar1900. All rights reserved. // #import "UIControl+runTimeProtect.h" #import "objc/runtime.h" #define uxy_staticConstString(__string) static const char * __string = #__string; static NSDictionary *XY_DicControlEventString = nil; static NSDictionary *XY_DicControlStringEvent = nil; #pragma mark- @implementation UIControl (XYExtension) + (void)load { XY_DicControlEventString = @{@(UIControlEventTouchDown): @"UIControlEventTouchDown", @(UIControlEventTouchDownRepeat): @"UIControlEventTouchDownRepeat", @(UIControlEventTouchDragInside): @"UIControlEventTouchDragInside", @(UIControlEventTouchDragOutside): @"UIControlEventTouchDragOutside", @(UIControlEventTouchDragEnter): @"UIControlEventTouchDragEnter", @(UIControlEventTouchDragExit): @"UIControlEventTouchDragExit", @(UIControlEventTouchUpInside): @"UIControlEventTouchUpInside", @(UIControlEventTouchUpOutside): @"UIControlEventTouchUpOutside", @(UIControlEventTouchCancel): @"UIControlEventTouchCancel", @(UIControlEventValueChanged): @"UIControlEventValueChanged", @(UIControlEventEditingDidBegin): @"UIControlEventEditingDidBegin", @(UIControlEventEditingChanged): @"UIControlEventEditingChanged", @(UIControlEventEditingDidEnd): @"UIControlEventEditingDidEnd", @(UIControlEventEditingDidEndOnExit): @"UIControlEventEditingDidEndOnExit", @(UIControlEventAllTouchEvents): @"UIControlEventAllTouchEvents", @(UIControlEventAllEditingEvents): @"UIControlEventAllEditingEvents", @(UIControlEventApplicationReserved): @"UIControlEventApplicationReserved", @(UIControlEventSystemReserved): @"UIControlEventSystemReserved", @(UIControlEventAllEvents): @"UIControlEventAllEvents" }; XY_DicControlStringEvent = @{@"UIControlEventTouchDown": @(UIControlEventTouchDown), @"UIControlEventTouchDownRepeat": @(UIControlEventTouchDownRepeat), @"UIControlEventTouchDragInside": @(UIControlEventTouchDragInside), @"UIControlEventTouchDragOutside": @(UIControlEventTouchDragOutside), @"UIControlEventTouchDragEnter": @(UIControlEventTouchDragEnter), @"UIControlEventTouchDragExit": @(UIControlEventTouchDragExit), @"UIControlEventTouchUpInside": @(UIControlEventTouchUpInside), @"UIControlEventTouchUpOutside": @(UIControlEventTouchUpOutside), @"UIControlEventTouchCancel": @(UIControlEventTouchCancel), @"UIControlEventValueChanged": @(UIControlEventValueChanged), @"UIControlEventEditingDidBegin": @(UIControlEventEditingDidBegin), @"UIControlEventEditingChanged": @(UIControlEventEditingChanged), @"UIControlEventEditingDidEnd": @(UIControlEventEditingDidEnd), @"UIControlEventEditingDidEndOnExit": @(UIControlEventEditingDidEndOnExit), @"UIControlEventAllTouchEvents": @(UIControlEventAllTouchEvents), @"UIControlEventAllEditingEvents": @(UIControlEventAllEditingEvents), @"UIControlEventApplicationReserved": @(UIControlEventApplicationReserved), @"UIControlEventSystemReserved": @(UIControlEventSystemReserved), @"UIControlEventAllEvents": @(UIControlEventAllEvents) }; Method a = class_getInstanceMethod([UIControl class], @selector(sendAction:to:forEvent:)); Method b = class_getInstanceMethod([UIControl class], @selector(__uxy_sendAction:to:forEvent:)); method_exchangeImplementations(a, b); } uxy_staticConstString(UIControl_key_events) - (void)dealloc { NSMutableDictionary *opreations = (NSMutableDictionary*)objc_getAssociatedObject(self, UIControl_key_events); if (opreations) { [opreations enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { [self uxy_removeHandlerForEvent:[UIControl __uxy_eventWithName:key]]; }]; objc_setAssociatedObject(self, UIControl_key_events, nil, OBJC_ASSOCIATION_ASSIGN); } } - (void)uxy_handleControlEvent:(UIControlEvents)event withBlock:(void(^)(id sender))block { NSString *methodName = [UIControl __uxy_eventName:event]; NSMutableDictionary *opreations = (NSMutableDictionary*)objc_getAssociatedObject(self, UIControl_key_events); if(opreations == nil) { opreations = [NSMutableDictionary dictionaryWithCapacity:2]; objc_setAssociatedObject(self, UIControl_key_events, opreations, OBJC_ASSOCIATION_ASSIGN); } [opreations setObject:[block copy] forKey:methodName]; [self addTarget:self action:NSSelectorFromString(methodName) forControlEvents:event]; } - (void)uxy_removeHandlerForEvent:(UIControlEvents)event { NSString *methodName = [UIControl __uxy_eventName:event]; NSMutableDictionary *opreations = (NSMutableDictionary*)objc_getAssociatedObject(self, UIControl_key_events); if(opreations == nil) { opreations = [NSMutableDictionary dictionaryWithCapacity:2]; objc_setAssociatedObject(self, UIControl_key_events, opreations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } [opreations removeObjectForKey:methodName]; [self removeTarget:self action:NSSelectorFromString(methodName) forControlEvents:event]; } uxy_staticConstString(UIControl_acceptEventInterval) - (NSTimeInterval)uxy_acceptEventInterval { return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue]; } - (void)setUxy_acceptEventInterval:(NSTimeInterval)uxy_acceptEventInterval { objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(uxy_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } #pragma mark - private // todo 命名待重构 - (void)UIControlEventTouchDown{[self __uxy_callActionBlock:UIControlEventTouchDown];} - (void)UIControlEventTouchDownRepeat{[self __uxy_callActionBlock:UIControlEventTouchDownRepeat];} - (void)UIControlEventTouchDragInside{[self __uxy_callActionBlock:UIControlEventTouchDragInside];} - (void)UIControlEventTouchDragOutside{[self __uxy_callActionBlock:UIControlEventTouchDragOutside];} - (void)UIControlEventTouchDragEnter{[self __uxy_callActionBlock:UIControlEventTouchDragEnter];} - (void)UIControlEventTouchDragExit{[self __uxy_callActionBlock:UIControlEventTouchDragExit];} - (void)UIControlEventTouchUpInside{[self __uxy_callActionBlock:UIControlEventTouchUpInside];} - (void)UIControlEventTouchUpOutside{[self __uxy_callActionBlock:UIControlEventTouchUpOutside];} - (void)UIControlEventTouchCancel{[self __uxy_callActionBlock:UIControlEventTouchCancel];} - (void)UIControlEventValueChanged{[self __uxy_callActionBlock:UIControlEventValueChanged];} - (void)UIControlEventEditingDidBegin{[self __uxy_callActionBlock:UIControlEventEditingDidBegin];} - (void)UIControlEventEditingChanged{[self __uxy_callActionBlock:UIControlEventEditingChanged];} - (void)UIControlEventEditingDidEnd{[self __uxy_callActionBlock:UIControlEventEditingDidEnd];} - (void)UIControlEventEditingDidEndOnExit{[self __uxy_callActionBlock:UIControlEventEditingDidEndOnExit];} - (void)UIControlEventAllTouchEvents{[self __uxy_callActionBlock:UIControlEventAllTouchEvents];} - (void)UIControlEventAllEditingEvents{[self __uxy_callActionBlock:UIControlEventAllEditingEvents];} - (void)UIControlEventApplicationReserved{[self __uxy_callActionBlock:UIControlEventApplicationReserved];} - (void)UIControlEventSystemReserved{[self __uxy_callActionBlock:UIControlEventSystemReserved];} - (void)UIControlEventAllEvents{[self __uxy_callActionBlock:UIControlEventAllEvents];} - (void)__uxy_callActionBlock:(UIControlEvents)event { NSMutableDictionary *opreations = (NSMutableDictionary*)objc_getAssociatedObject(self, UIControl_key_events); if(opreations == nil) return; void(^block)(id sender) = [opreations objectForKey:[UIControl __uxy_eventName:event]]; block ? block(self) : nil ; } + (NSString *)__uxy_eventName:(UIControlEvents)event { return [XY_DicControlEventString objectForKey:@(event)]; } + (UIControlEvents)__uxy_eventWithName:(NSString *)name { return [[XY_DicControlStringEvent objectForKey:name] integerValue]; } uxy_staticConstString(UIControl_acceptedEventTime) - (NSTimeInterval)uxy_acceptedEventTime { return [objc_getAssociatedObject(self, UIControl_acceptedEventTime) doubleValue]; } - (void)setUxy_acceptedEventTime:(NSTimeInterval)uxy_acceptedEventTime { objc_setAssociatedObject(self, UIControl_acceptedEventTime, @(uxy_acceptedEventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)__uxy_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { NSString *actionString = NSStringFromSelector(action); if ([actionString isMatchedByRegex:@"nbs_"]) { return; /** * bug:5316(【需求】SDK集成) 解决听云冲突 */ } if (NSDate.date.timeIntervalSince1970 - self.uxy_acceptedEventTime < self.uxy_acceptEventInterval) return; if (self.uxy_acceptEventInterval > 0) { self.uxy_acceptedEventTime = NSDate.date.timeIntervalSince1970; NSLog(@"%f",self.uxy_acceptedEventTime); } [self __uxy_sendAction:action to:target forEvent:event]; } @end