LKS_EventHandlerMaker.m 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //
  2. // LKS_EventHandlerMaker.m
  3. // LookinServer
  4. //
  5. // Created by Li Kai on 2019/8/7.
  6. // https://lookin.work
  7. //
  8. #import "LKS_EventHandlerMaker.h"
  9. #import "LookinTuple.h"
  10. #import "LookinEventHandler.h"
  11. #import "LookinObject.h"
  12. #import "UIGestureRecognizer+LookinServer.h"
  13. #import "LookinWeakContainer.h"
  14. #import "LookinIvarTrace.h"
  15. #import "LookinServerDefines.h"
  16. @implementation LKS_EventHandlerMaker
  17. + (NSArray<LookinEventHandler *> *)makeForView:(UIView *)view {
  18. if (!view) {
  19. return nil;
  20. }
  21. NSMutableArray<LookinEventHandler *> *allHandlers = nil;
  22. if ([view isKindOfClass:[UIControl class]]) {
  23. NSArray<LookinEventHandler *> *targetActionHandlers = [self _targetActionHandlersForControl:(UIControl *)view];
  24. if (targetActionHandlers.count) {
  25. if (!allHandlers) {
  26. allHandlers = [NSMutableArray array];
  27. }
  28. [allHandlers addObjectsFromArray:targetActionHandlers];
  29. }
  30. }
  31. NSArray<LookinEventHandler *> *gestureHandlers = [self _gestureHandlersForView:view];
  32. if (gestureHandlers.count) {
  33. if (!allHandlers) {
  34. allHandlers = [NSMutableArray array];
  35. }
  36. [allHandlers addObjectsFromArray:gestureHandlers];
  37. }
  38. return allHandlers.copy;
  39. }
  40. + (NSArray<LookinEventHandler *> *)_gestureHandlersForView:(UIView *)view {
  41. if (view.gestureRecognizers.count == 0) {
  42. return nil;
  43. }
  44. NSArray<LookinEventHandler *> *handlers = [view.gestureRecognizers lookin_map:^id(NSUInteger idx, __kindof UIGestureRecognizer *recognizer) {
  45. LookinEventHandler *handler = [LookinEventHandler new];
  46. handler.handlerType = LookinEventHandlerTypeGesture;
  47. handler.eventName = [recognizer lks_shortClassName];
  48. handler.targetActions = [[recognizer lks_targetActions] lookin_map:^id(NSUInteger idx, LookinTwoTuple *rawTuple) {
  49. NSObject *target = ((LookinWeakContainer *)rawTuple.first).object;
  50. if (!target) {
  51. // 该 target 已被释放
  52. return nil;
  53. }
  54. LookinStringTwoTuple *newTuple = [LookinStringTwoTuple new];
  55. newTuple.first = [LKS_Helper descriptionOfObject:target];
  56. newTuple.second = (NSString *)rawTuple.second;
  57. return newTuple;
  58. }];
  59. handler.inheritedRecognizerName = [self _inheritedRecognizerNameForRecognizer:recognizer];
  60. handler.gestureRecognizerIsEnabled = recognizer.enabled;
  61. if (recognizer.delegate) {
  62. handler.gestureRecognizerDelegator = [LKS_Helper descriptionOfObject:recognizer.delegate];
  63. }
  64. handler.recognizerIvarTraces = [recognizer.lks_ivarTraces lookin_map:^id(NSUInteger idx, LookinIvarTrace *trace) {
  65. return [NSString stringWithFormat:@"(%@ *) -> %@", trace.hostClassName, trace.ivarName];
  66. }];
  67. handler.recognizerOid = [recognizer lks_registerOid];
  68. return handler;
  69. }];
  70. return handlers;
  71. }
  72. + (NSString *)_inheritedRecognizerNameForRecognizer:(UIGestureRecognizer *)recognizer {
  73. if (!recognizer) {
  74. NSAssert(NO, @"");
  75. return nil;
  76. }
  77. static NSArray<Class> *baseRecognizers;
  78. static dispatch_once_t onceToken;
  79. dispatch_once(&onceToken, ^{
  80. // 注意这里 UIScreenEdgePanGestureRecognizer 在 UIPanGestureRecognizer 前面,因为 UIScreenEdgePanGestureRecognizer 继承于 UIPanGestureRecognizer
  81. #if TARGET_OS_TV
  82. baseRecognizers = @[[UILongPressGestureRecognizer class],
  83. [UIPanGestureRecognizer class],
  84. [UISwipeGestureRecognizer class],
  85. [UITapGestureRecognizer class]];
  86. #else
  87. baseRecognizers = @[[UILongPressGestureRecognizer class],
  88. [UIScreenEdgePanGestureRecognizer class],
  89. [UIPanGestureRecognizer class],
  90. [UISwipeGestureRecognizer class],
  91. [UIRotationGestureRecognizer class],
  92. [UIPinchGestureRecognizer class],
  93. [UITapGestureRecognizer class]];
  94. #endif
  95. });
  96. __block NSString *result = @"UIGestureRecognizer";
  97. [baseRecognizers enumerateObjectsUsingBlock:^(Class _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  98. if ([recognizer isMemberOfClass:obj]) {
  99. // 自身就是基本款,则直接置为 nil
  100. result = nil;
  101. *stop = YES;
  102. return;
  103. }
  104. if ([recognizer isKindOfClass:obj]) {
  105. result = NSStringFromClass(obj);
  106. *stop = YES;
  107. return;
  108. }
  109. }];
  110. return result;
  111. }
  112. + (NSArray<LookinEventHandler *> *)_targetActionHandlersForControl:(UIControl *)control {
  113. static dispatch_once_t onceToken;
  114. static NSArray<NSNumber *> *allEvents = nil;
  115. dispatch_once(&onceToken,^{
  116. allEvents = @[@(UIControlEventTouchDown), @(UIControlEventTouchDownRepeat), @(UIControlEventTouchDragInside), @(UIControlEventTouchDragOutside), @(UIControlEventTouchDragEnter), @(UIControlEventTouchDragExit), @(UIControlEventTouchUpInside), @(UIControlEventTouchUpOutside), @(UIControlEventTouchCancel), @(UIControlEventValueChanged), @(UIControlEventEditingDidBegin), @(UIControlEventEditingChanged), @(UIControlEventEditingDidEnd), @(UIControlEventEditingDidEndOnExit)];
  117. if (@available(iOS 9.0, *)) {
  118. allEvents = [allEvents arrayByAddingObject:@(UIControlEventPrimaryActionTriggered)];
  119. }
  120. });
  121. NSSet *allTargets = control.allTargets;
  122. if (!allTargets.count) {
  123. return nil;
  124. }
  125. NSMutableArray<LookinEventHandler *> *handlers = [NSMutableArray array];
  126. [allEvents enumerateObjectsUsingBlock:^(NSNumber * _Nonnull eventNum, NSUInteger idx, BOOL * _Nonnull stop) {
  127. UIControlEvents event = [eventNum unsignedIntegerValue];
  128. NSMutableArray<LookinStringTwoTuple *> *targetActions = [NSMutableArray array];
  129. [allTargets enumerateObjectsUsingBlock:^(id _Nonnull target, BOOL * _Nonnull stop) {
  130. NSArray<NSString *> *actions = [control actionsForTarget:target forControlEvent:event];
  131. [actions enumerateObjectsUsingBlock:^(NSString * _Nonnull action, NSUInteger idx, BOOL * _Nonnull stop) {
  132. LookinStringTwoTuple *tuple = [LookinStringTwoTuple new];
  133. tuple.first = [LKS_Helper descriptionOfObject:target];
  134. tuple.second = action;
  135. [targetActions addObject:tuple];
  136. }];
  137. }];
  138. if (targetActions.count) {
  139. LookinEventHandler *handler = [LookinEventHandler new];
  140. handler.handlerType = LookinEventHandlerTypeTargetAction;
  141. handler.eventName = [self _nameFromControlEvent:event];
  142. handler.targetActions = targetActions.copy;
  143. [handlers addObject:handler];
  144. }
  145. }];
  146. return handlers;
  147. }
  148. + (NSString *)_nameFromControlEvent:(UIControlEvents)event {
  149. static dispatch_once_t onceToken;
  150. static NSDictionary<NSNumber *, NSString *> *eventsAndNames = nil;
  151. dispatch_once(&onceToken,^{
  152. NSMutableDictionary<NSNumber *, NSString *> *eventsAndNames_m = @{
  153. @(UIControlEventTouchDown): @"UIControlEventTouchDown",
  154. @(UIControlEventTouchDownRepeat): @"UIControlEventTouchDownRepeat",
  155. @(UIControlEventTouchDragInside): @"UIControlEventTouchDragInside",
  156. @(UIControlEventTouchDragOutside): @"UIControlEventTouchDragOutside",
  157. @(UIControlEventTouchDragEnter): @"UIControlEventTouchDragEnter",
  158. @(UIControlEventTouchDragExit): @"UIControlEventTouchDragExit",
  159. @(UIControlEventTouchUpInside): @"UIControlEventTouchUpInside",
  160. @(UIControlEventTouchUpOutside): @"UIControlEventTouchUpOutside",
  161. @(UIControlEventTouchCancel): @"UIControlEventTouchCancel",
  162. @(UIControlEventValueChanged): @"UIControlEventValueChanged",
  163. @(UIControlEventEditingDidBegin): @"UIControlEventEditingDidBegin",
  164. @(UIControlEventEditingChanged): @"UIControlEventEditingChanged",
  165. @(UIControlEventEditingDidEnd): @"UIControlEventEditingDidEnd",
  166. @(UIControlEventEditingDidEndOnExit): @"UIControlEventEditingDidEndOnExit",
  167. }.mutableCopy;
  168. if (@available(iOS 9.0, *)) {
  169. eventsAndNames_m[@(UIControlEventPrimaryActionTriggered)] = @"UIControlEventPrimaryActionTriggered";
  170. }
  171. eventsAndNames = eventsAndNames_m.copy;
  172. });
  173. NSString *name = eventsAndNames[@(event)];
  174. return name;
  175. }
  176. @end