DoraemonKit部分功能核心原理解析

1,网络监听功能
用处:网络检测,mock数据,大图片检测
原理:有一个系统类NSURLProtocol,它属于URL Loading System的一部分,默认通过NSURLSession等网络请求都是会默认创建一个NSURLProtocol实例进行操作,如果自己创建一个NSURLProtocol的子类并进行注册,就可以监听app内所有网络请求
参考:
https://blog.csdn.net/u014600626/article/details/108195234
2,判断是否卡顿主线程
DoraemonKit的实现逻辑很巧妙.有个类DoraemonPingThread,类似终端操作的ping指令,创建一个子线程,在子线程内访问主线程,如果在一定时间内访问成功则表示不卡顿,如果在一定时间内没有访问成功则代表卡顿.

- (void)main {
    //判断是否需要上报
    __weak typeof(self) weakSelf = self;
    void (^ verifyReport)(void) = ^() {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf.reportInfo.length > 0) {
            if (strongSelf.handler) {
                double responseTimeValue = floor([[NSDate date] timeIntervalSince1970] * 1000);
                double duration = (responseTimeValue - strongSelf.startTimeValue) / 1000.0;
                strongSelf.handler(@{
                                     @"title": [DoraemonUtil dateFormatNow].length > 0 ? [DoraemonUtil dateFormatNow] : @"",
                                     @"duration": [NSString stringWithFormat:@"%.2f",duration],
                                     @"content": strongSelf.reportInfo
                                     });
            }
            strongSelf.reportInfo = @"";
        }
    };
    
    while (!self.cancelled) {
        if (_isApplicationInActive) {
            self.mainThreadBlock = YES;
            self.reportInfo = @"";
            self.startTimeValue = floor([[NSDate date] timeIntervalSince1970] * 1000);
            dispatch_async(dispatch_get_main_queue(), ^{
                self.mainThreadBlock = NO;
                verifyReport();
                dispatch_semaphore_signal(self.semaphore);
            });
            [NSThread sleepForTimeInterval:self.threshold];
            if (self.isMainThreadBlock) {
                self.reportInfo = [BSBacktraceLogger bs_backtraceOfMainThread];
            }
            dispatch_semaphore_wait(self.semaphore, dispatch_time(DISPATCH_TIME_NOW, 5.0 * NSEC_PER_SEC));
            {
                //卡顿超时情况;
                verifyReport();
            }
        } else {
            [NSThread sleepForTimeInterval:self.threshold];
        }
    }
}

3,oc内存泄漏
原理:hooknavigation相关方法(popViewControllerAnimated等相关方法),UIViewController相关方法(viewDidDisappear等相关方法),说明这个vc绑定的属性以及相关子view将要dealloc,然后通过runtime相关方法拿到这些属性和子view调用一个after延时方法,如果之后该对象dealloc了则没有内存泄漏如果没死则有.如果有则会弹出弹窗提示,并通过FBRetainCycleDetector库拿到引用环.

再说一下FBRetainCycleDetector原理:
简单说,根据传入的可能有引用循环的对象,深度遍历所有持有的属性,然后判断是不是有换.主要分为如下几类
1,block的引用属性:因为block也是对象,通过强制类型转换把block转换为BlockLiteral结构体,根据dispose_helperApi会自动管理block持有的引用对象的引用,如果是强引用,会调用release方法,根据这个现象可以判断改成员属性是不是强引用

 void **blockReference = block;
  NSIndexSet *strongLayout = _GetBlockStrongLayout(block);
  [strongLayout enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
    void **reference = &blockReference[idx];

    if (reference && (*reference)) {
      id object = (id)(*reference);

      if (object) {
        [results addObject:object];
      }
    }
  }];


static NSIndexSet *_GetBlockStrongLayout(void *block) {
  struct BlockLiteral *blockLiteral = block;

  /**
   BLOCK_HAS_CTOR - Block has a C++ constructor/destructor, which gives us a good chance it retains
   objects that are not pointer aligned, so omit them.

   !BLOCK_HAS_COPY_DISPOSE - Block doesn't have a dispose function, so it does not retain objects and
   we are not able to blackbox it.
   */
  if ((blockLiteral->flags & BLOCK_HAS_CTOR)
      || !(blockLiteral->flags & BLOCK_HAS_COPY_DISPOSE)) {
    return nil;
  }

  void (*dispose_helper)(void *src) = blockLiteral->descriptor->dispose_helper;
  const size_t ptrSize = sizeof(void *);

  // Figure out the number of pointers it takes to fill out the object, rounding up.
  const size_t elements = (blockLiteral->descriptor->size + ptrSize - 1) / ptrSize;

  // Create a fake object of the appropriate length.
  void *obj[elements];
  void *detectors[elements];

  for (size_t i = 0; i < elements; ++i) {
    FBBlockStrongRelationDetector *detector = [FBBlockStrongRelationDetector new];
    obj[i] = detectors[i] = detector;
  }

  @autoreleasepool {
    dispose_helper(obj);
  }

  // Run through the release detectors and add each one that got released to the object's
  // strong ivar layout.
  NSMutableIndexSet *layout = [NSMutableIndexSet indexSet];

  for (size_t i = 0; i < elements; ++i) {
    FBBlockStrongRelationDetector *detector = (FBBlockStrongRelationDetector *)(detectors[i]);
    if (detector.isStrong) {
      [layout addIndex:i];
    }

    // Destroy detectors
    [detector trueRelease];
  }

  return layout;
}

struct BlockLiteral {
  void *isa;  // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
  int flags;
  int reserved;
  void (*invoke)(void *, ...);
  struct BlockDescriptor *descriptor;
  // imported variables
};

struct BlockDescriptor {
  unsigned long int reserved;                // NULL
  unsigned long int size;
  // optional helper functions
  void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
  void (*dispose_helper)(void *src);         // IFF (1<<25)
  const char *signature;                     // IFF (1<<30)
};

2,timer的引用属性:通过CFRunLoopTimerContext,拿到timer的content,之后拿到target对象
3,Association关联对象持有的强引用对象:通过fishhook,hook系统的api,自己存储一份关联对象的属性map
4,普通的强引用对象:通过runtime的api那个他的属性(class_copyIvarList)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容