LookinMethodTraceRecord.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #ifdef SHOULD_COMPILE_LOOKIN_SERVER
  2. //
  3. // LookinMethodTraceRecord.m
  4. // Lookin
  5. //
  6. // Created by Li Kai on 2019/5/27.
  7. // https://lookin.work
  8. //
  9. #import "LookinMethodTraceRecord.h"
  10. #import "NSArray+Lookin.h"
  11. @implementation LookinMethodTraceRecordStackItem
  12. @end
  13. @implementation LookinMethodTraceRecord
  14. - (void)encodeWithCoder:(NSCoder *)aCoder {
  15. [aCoder encodeObject:self.targetAddress forKey:@"targetAddress"];
  16. [aCoder encodeObject:self.selClassName forKey:@"selClassName"];
  17. [aCoder encodeObject:self.selName forKey:@"selName"];
  18. [aCoder encodeObject:self.args forKey:@"args"];
  19. [aCoder encodeObject:self.callStacks forKey:@"callStacks"];
  20. [aCoder encodeObject:self.date forKey:@"date"];
  21. }
  22. - (instancetype)initWithCoder:(NSCoder *)aDecoder {
  23. if (self = [super init]) {
  24. self.targetAddress = [aDecoder decodeObjectForKey:@"targetAddress"];
  25. self.selClassName = [aDecoder decodeObjectForKey:@"selClassName"];
  26. self.selName = [aDecoder decodeObjectForKey:@"selName"];
  27. self.args = [aDecoder decodeObjectForKey:@"args"];
  28. self.callStacks = [aDecoder decodeObjectForKey:@"callStacks"];
  29. self.date = [aDecoder decodeObjectForKey:@"date"];
  30. _combinedTitle = [self _makeCombinedTitle];
  31. }
  32. return self;
  33. }
  34. + (BOOL)supportsSecureCoding {
  35. return YES;
  36. }
  37. - (NSArray<LookinMethodTraceRecordStackItem *> *)briefFormattedCallStacks {
  38. return [self _formattedStacksFromRawStacks:self.callStacks brief:YES];
  39. }
  40. - (NSArray<LookinMethodTraceRecordStackItem *> *)completeFormattedCallStacks {
  41. return [self _formattedStacksFromRawStacks:self.callStacks brief:NO];
  42. }
  43. - (NSString *)_makeCombinedTitle {
  44. NSString *selString;
  45. if (self.args.count) {
  46. NSArray<NSString *> *selParts = [[self.selName componentsSeparatedByString:@":"] lookin_filter:^BOOL(NSString *obj) {
  47. return obj.length > 0;
  48. }];
  49. NSMutableString *mutableSelString = [NSMutableString string];
  50. [selParts enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  51. [mutableSelString appendString:obj];
  52. NSString *arg = [self.args lookin_safeObjectAtIndex:idx];
  53. if (arg) {
  54. [mutableSelString appendFormat:@":%@", arg];
  55. } else {
  56. [mutableSelString appendString:@":?"];
  57. }
  58. if (idx < selParts.count - 1) {
  59. [mutableSelString appendString:@" "];
  60. }
  61. }];
  62. selString = mutableSelString.copy;
  63. } else {
  64. selString = self.selName;
  65. }
  66. NSString *combinedTitle = [NSString stringWithFormat:@"[(%@ *)%@ %@]", self.selClassName, self.targetAddress, selString];
  67. return combinedTitle;
  68. }
  69. - (NSArray<LookinMethodTraceRecordStackItem *> *)_formattedStacksFromRawStacks:(NSArray<NSString *> *)strings brief:(BOOL)brief {
  70. NSMutableArray<LookinMethodTraceRecordStackItem *> *items = [NSMutableArray array];
  71. [items addObject:({
  72. LookinMethodTraceRecordStackItem *item = [LookinMethodTraceRecordStackItem new];
  73. item.idx = 0;
  74. item.detail = [NSString stringWithFormat:@"-[%@ %@]", self.selClassName, self.selName];
  75. item;
  76. })];
  77. [items addObjectsFromArray:[strings lookin_map:^id(NSUInteger idx, NSString *value) {
  78. if (idx <= 2) {
  79. // 过滤掉 Lookin 相关
  80. return nil;
  81. }
  82. LookinMethodTraceRecordStackItem *item = [self _formattedStackItemFromRawString:value];
  83. item.idx = idx - 2;
  84. return item;
  85. }]];
  86. if (!brief) {
  87. return items.copy;
  88. }
  89. NSMutableArray<LookinMethodTraceRecordStackItem *> *briefItems = [NSMutableArray array];
  90. [items enumerateObjectsUsingBlock:^(LookinMethodTraceRecordStackItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  91. if ([obj.category isEqualToString:@"???"]) {
  92. return;
  93. }
  94. if (!obj.isSystemItem) {
  95. [briefItems addObject:obj];
  96. return;
  97. }
  98. if (!briefItems.lastObject.isSystemItem) {
  99. [briefItems addObject:obj];
  100. return;
  101. }
  102. LookinMethodTraceRecordStackItem *nextItem = [items lookin_safeObjectAtIndex:idx + 1];
  103. if (!nextItem || !nextItem.isSystemItem) {
  104. [briefItems addObject:obj];
  105. LookinMethodTraceRecordStackItem *prevItem = [items lookin_safeObjectAtIndex:idx - 1];
  106. LookinMethodTraceRecordStackItem *prevPrevItem = [items lookin_safeObjectAtIndex:idx - 2];
  107. if (prevItem && prevPrevItem && prevItem.isSystemItem && prevPrevItem.isSystemItem) {
  108. obj.isSystemSeriesEnding = YES;
  109. }
  110. }
  111. }];
  112. return briefItems.copy;
  113. }
  114. - (LookinMethodTraceRecordStackItem *)_formattedStackItemFromRawString:(NSString *)string {
  115. LookinMethodTraceRecordStackItem *item = [LookinMethodTraceRecordStackItem new];
  116. item.category = ({
  117. NSArray<NSString *> *strs = [[string componentsSeparatedByString:@" "] lookin_filter:^BOOL(NSString *obj) {
  118. return obj.length > 0;
  119. }];
  120. strs[1];
  121. });
  122. item.detail = ({
  123. NSString *tmpStr = [[string componentsSeparatedByString:@" "].lastObject stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
  124. NSUInteger loc0 = [tmpStr rangeOfString:@" "].location;
  125. NSUInteger loc1 = [tmpStr rangeOfString:@" + "].location;
  126. NSString *str = [tmpStr substringWithRange:NSMakeRange(loc0 + 1, loc1 - loc0)];
  127. str;
  128. });
  129. if ([item.category isEqualToString:@"UIKitCore"] ||
  130. [item.category isEqualToString:@"libdyld.dylib"] ||
  131. [item.category isEqualToString:@"CoreFoundation"]) {
  132. item.isSystemItem = YES;
  133. }
  134. return item;
  135. }
  136. @end
  137. #endif /* SHOULD_COMPILE_LOOKIN_SERVER */