LKS_AttrModificationHandler.m 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //
  2. // LKS_AttrModificationHandler.m
  3. // LookinServer
  4. //
  5. // Created by Li Kai on 2019/6/12.
  6. // https://lookin.work
  7. //
  8. #import "LKS_AttrModificationHandler.h"
  9. #import "UIColor+LookinServer.h"
  10. #import "LookinAttributeModification.h"
  11. #import "LKS_AttrGroupsMaker.h"
  12. #import "LookinDisplayItemDetail.h"
  13. #import "LookinStaticAsyncUpdateTask.h"
  14. #import "LookinServerDefines.h"
  15. @implementation LKS_AttrModificationHandler
  16. + (void)handleModification:(LookinAttributeModification *)modification completion:(void (^)(LookinDisplayItemDetail *data, NSError *error))completion {
  17. if (!completion) {
  18. NSAssert(NO, @"");
  19. return;
  20. }
  21. if (!modification || ![modification isKindOfClass:[LookinAttributeModification class]]) {
  22. completion(nil, LookinErr_Inner);
  23. return;
  24. }
  25. NSObject *receiver = [NSObject lks_objectWithOid:modification.targetOid];
  26. if (!receiver) {
  27. completion(nil, LookinErr_ObjNotFound);
  28. return;
  29. }
  30. NSMethodSignature *setterSignature = [receiver methodSignatureForSelector:modification.setterSelector];
  31. NSInvocation *setterInvocation = [NSInvocation invocationWithMethodSignature:setterSignature];
  32. setterInvocation.target = receiver;
  33. setterInvocation.selector = modification.setterSelector;
  34. if (setterSignature.numberOfArguments != 3 || ![receiver respondsToSelector:modification.setterSelector]) {
  35. completion(nil, LookinErr_Inner);
  36. return;
  37. }
  38. switch (modification.attrType) {
  39. case LookinAttrTypeNone:
  40. case LookinAttrTypeVoid: {
  41. completion(nil, LookinErr_Inner);
  42. return;
  43. }
  44. case LookinAttrTypeChar: {
  45. char expectedValue = [(NSNumber *)modification.value charValue];
  46. [setterInvocation setArgument:&expectedValue atIndex:2];
  47. break;
  48. }
  49. case LookinAttrTypeInt:
  50. case LookinAttrTypeEnumInt: {
  51. int expectedValue = [(NSNumber *)modification.value intValue];
  52. [setterInvocation setArgument:&expectedValue atIndex:2];
  53. break;
  54. }
  55. case LookinAttrTypeShort: {
  56. short expectedValue = [(NSNumber *)modification.value shortValue];
  57. [setterInvocation setArgument:&expectedValue atIndex:2];
  58. break;
  59. }
  60. case LookinAttrTypeLong:
  61. case LookinAttrTypeEnumLong: {
  62. long expectedValue = [(NSNumber *)modification.value longValue];
  63. [setterInvocation setArgument:&expectedValue atIndex:2];
  64. break;
  65. }
  66. case LookinAttrTypeLongLong: {
  67. long long expectedValue = [(NSNumber *)modification.value longLongValue];
  68. [setterInvocation setArgument:&expectedValue atIndex:2];
  69. break;
  70. }
  71. case LookinAttrTypeUnsignedChar: {
  72. unsigned char expectedValue = [(NSNumber *)modification.value unsignedCharValue];
  73. [setterInvocation setArgument:&expectedValue atIndex:2];
  74. break;
  75. }
  76. case LookinAttrTypeUnsignedInt: {
  77. unsigned int expectedValue = [(NSNumber *)modification.value unsignedIntValue];
  78. [setterInvocation setArgument:&expectedValue atIndex:2];
  79. break;
  80. }
  81. case LookinAttrTypeUnsignedShort: {
  82. unsigned short expectedValue = [(NSNumber *)modification.value unsignedShortValue];
  83. [setterInvocation setArgument:&expectedValue atIndex:2];
  84. break;
  85. }
  86. case LookinAttrTypeUnsignedLong: {
  87. unsigned long expectedValue = [(NSNumber *)modification.value unsignedLongValue];
  88. [setterInvocation setArgument:&expectedValue atIndex:2];
  89. break;
  90. }
  91. case LookinAttrTypeUnsignedLongLong: {
  92. unsigned long long expectedValue = [(NSNumber *)modification.value unsignedLongLongValue];
  93. [setterInvocation setArgument:&expectedValue atIndex:2];
  94. break;
  95. }
  96. case LookinAttrTypeFloat: {
  97. float expectedValue = [(NSNumber *)modification.value floatValue];
  98. [setterInvocation setArgument:&expectedValue atIndex:2];
  99. break;
  100. }
  101. case LookinAttrTypeDouble: {
  102. double expectedValue = [(NSNumber *)modification.value doubleValue];
  103. [setterInvocation setArgument:&expectedValue atIndex:2];
  104. break;
  105. }
  106. case LookinAttrTypeBOOL: {
  107. BOOL expectedValue = [(NSNumber *)modification.value boolValue];
  108. [setterInvocation setArgument:&expectedValue atIndex:2];
  109. break;
  110. }
  111. case LookinAttrTypeSel: {
  112. SEL expectedValue = NSSelectorFromString(modification.value);
  113. [setterInvocation setArgument:&expectedValue atIndex:2];
  114. break;
  115. }
  116. case LookinAttrTypeClass: {
  117. Class expectedValue = NSClassFromString(modification.value);
  118. [setterInvocation setArgument:&expectedValue atIndex:2];
  119. break;
  120. }
  121. case LookinAttrTypeCGPoint: {
  122. CGPoint expectedValue = [(NSValue *)modification.value CGPointValue];
  123. [setterInvocation setArgument:&expectedValue atIndex:2];
  124. break;
  125. }
  126. case LookinAttrTypeCGVector: {
  127. CGVector expectedValue = [(NSValue *)modification.value CGVectorValue];
  128. [setterInvocation setArgument:&expectedValue atIndex:2];
  129. break;
  130. }
  131. case LookinAttrTypeCGSize: {
  132. CGSize expectedValue = [(NSValue *)modification.value CGSizeValue];
  133. [setterInvocation setArgument:&expectedValue atIndex:2];
  134. break;
  135. }
  136. case LookinAttrTypeCGRect: {
  137. CGRect expectedValue = [(NSValue *)modification.value CGRectValue];
  138. [setterInvocation setArgument:&expectedValue atIndex:2];
  139. break;
  140. }
  141. case LookinAttrTypeCGAffineTransform: {
  142. CGAffineTransform expectedValue = [(NSValue *)modification.value CGAffineTransformValue];
  143. [setterInvocation setArgument:&expectedValue atIndex:2];
  144. break;
  145. }
  146. case LookinAttrTypeUIEdgeInsets: {
  147. UIEdgeInsets expectedValue = [(NSValue *)modification.value UIEdgeInsetsValue];
  148. [setterInvocation setArgument:&expectedValue atIndex:2];
  149. break;
  150. }
  151. case LookinAttrTypeUIOffset: {
  152. UIOffset expectedValue = [(NSValue *)modification.value UIOffsetValue];
  153. [setterInvocation setArgument:&expectedValue atIndex:2];
  154. break;
  155. }
  156. case LookinAttrTypeCustomObj:
  157. case LookinAttrTypeNSString: {
  158. NSObject *expectedValue = modification.value;
  159. [setterInvocation setArgument:&expectedValue atIndex:2];
  160. [setterInvocation retainArguments];
  161. break;
  162. }
  163. case LookinAttrTypeUIColor: {
  164. NSArray<NSNumber *> *rgba = modification.value;
  165. UIColor *expectedValue = [UIColor lks_colorFromRGBAComponents:rgba];
  166. [setterInvocation setArgument:&expectedValue atIndex:2];
  167. [setterInvocation retainArguments];
  168. break;
  169. }
  170. default: {
  171. completion(nil, LookinErr_Inner);
  172. return;
  173. }
  174. }
  175. NSError *error = nil;
  176. @try {
  177. [setterInvocation invoke];
  178. } @catch (NSException *exception) {
  179. NSString *errorMsg = [NSString stringWithFormat:LKS_Localized(@"<%@: %p>: an exception was raised when invoking %@. (%@)"), NSStringFromClass(receiver.class), receiver, NSStringFromSelector(modification.setterSelector), exception.reason];
  180. error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Exception userInfo:@{NSLocalizedDescriptionKey:LKS_Localized(@"The modification may failed."), NSLocalizedRecoverySuggestionErrorKey:errorMsg}];
  181. } @finally {
  182. }
  183. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  184. CALayer *layer = nil;
  185. if ([receiver isKindOfClass:[CALayer class]]) {
  186. layer = (CALayer *)receiver;
  187. } else if ([receiver isKindOfClass:[UIView class]]) {
  188. layer = ((UIView *)receiver).layer;
  189. } else {
  190. completion(nil, LookinErr_ObjNotFound);
  191. return;
  192. }
  193. // 比如试图更改 frame 时,这个改动很有可能触发用户业务的 relayout,因此这时 dispatch 一下以确保拿到的 attrGroups 数据是最新的
  194. LookinDisplayItemDetail *detail = [LookinDisplayItemDetail new];
  195. detail.displayItemOid = modification.targetOid;
  196. detail.attributesGroupList = [LKS_AttrGroupsMaker attrGroupsForLayer:layer];
  197. detail.frameValue = [NSValue valueWithCGRect:layer.frame];
  198. detail.boundsValue = [NSValue valueWithCGRect:layer.bounds];
  199. detail.hiddenValue = [NSNumber numberWithBool:layer.isHidden];
  200. detail.alphaValue = @(layer.opacity);
  201. completion(detail, error);
  202. });
  203. }
  204. + (void)handlePatchWithTasks:(NSArray<LookinStaticAsyncUpdateTask *> *)tasks block:(void (^)(LookinDisplayItemDetail *data))block {
  205. if (!block) {
  206. NSAssert(NO, @"");
  207. return;
  208. }
  209. [tasks enumerateObjectsUsingBlock:^(LookinStaticAsyncUpdateTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
  210. LookinDisplayItemDetail *itemDetail = [LookinDisplayItemDetail new];
  211. itemDetail.displayItemOid = task.oid;
  212. id object = [NSObject lks_objectWithOid:task.oid];
  213. if (!object || ![object isKindOfClass:[CALayer class]]) {
  214. block(itemDetail);
  215. return;
  216. }
  217. CALayer *layer = object;
  218. if (task.taskType == LookinStaticAsyncUpdateTaskTypeSoloScreenshot) {
  219. UIImage *image = [layer lks_soloScreenshotWithLowQuality:NO];
  220. itemDetail.soloScreenshot = image;
  221. } else if (task.taskType == LookinStaticAsyncUpdateTaskTypeGroupScreenshot) {
  222. UIImage *image = [layer lks_groupScreenshotWithLowQuality:NO];
  223. itemDetail.groupScreenshot = image;
  224. }
  225. block(itemDetail);
  226. }];
  227. }
  228. @end