DoraemonKit部分功能核心原理解析

1,網(wǎng)絡(luò)監(jiān)聽功能
用處:網(wǎng)絡(luò)檢測(cè),mock數(shù)據(jù),大圖片檢測(cè)
原理:有一個(gè)系統(tǒng)類NSURLProtocol,它屬于URL Loading System的一部分,默認(rèn)通過NSURLSession等網(wǎng)絡(luò)請(qǐng)求都是會(huì)默認(rèn)創(chuàng)建一個(gè)NSURLProtocol實(shí)例進(jìn)行操作,如果自己創(chuàng)建一個(gè)NSURLProtocol的子類并進(jìn)行注冊(cè),就可以監(jiān)聽app內(nèi)所有網(wǎng)絡(luò)請(qǐng)求
參考:
https://blog.csdn.net/u014600626/article/details/108195234
2,判斷是否卡頓主線程
DoraemonKit的實(shí)現(xiàn)邏輯很巧妙.有個(gè)類DoraemonPingThread,類似終端操作的ping指令,創(chuàng)建一個(gè)子線程,在子線程內(nèi)訪問主線程,如果在一定時(shí)間內(nèi)訪問成功則表示不卡頓,如果在一定時(shí)間內(nèi)沒有訪問成功則代表卡頓.

- (void)main {
    //判斷是否需要上報(bào)
    __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));
            {
                //卡頓超時(shí)情況;
                verifyReport();
            }
        } else {
            [NSThread sleepForTimeInterval:self.threshold];
        }
    }
}

3,oc內(nèi)存泄漏
原理:hooknavigation相關(guān)方法(popViewControllerAnimated等相關(guān)方法),UIViewController相關(guān)方法(viewDidDisappear等相關(guān)方法),說明這個(gè)vc綁定的屬性以及相關(guān)子view將要dealloc,然后通過runtime相關(guān)方法拿到這些屬性和子view調(diào)用一個(gè)after延時(shí)方法,如果之后該對(duì)象dealloc了則沒有內(nèi)存泄漏如果沒死則有.如果有則會(huì)彈出彈窗提示,并通過FBRetainCycleDetector庫拿到引用環(huán).

再說一下FBRetainCycleDetector原理:
簡單說,根據(jù)傳入的可能有引用循環(huán)的對(duì)象,深度遍歷所有持有的屬性,然后判斷是不是有換.主要分為如下幾類
1,block的引用屬性:因?yàn)閎lock也是對(duì)象,通過強(qiáng)制類型轉(zhuǎn)換把block轉(zhuǎn)換為BlockLiteral結(jié)構(gòu)體,根據(jù)dispose_helperApi會(huì)自動(dòng)管理block持有的引用對(duì)象的引用,如果是強(qiáng)引用,會(huì)調(diào)用release方法,根據(jù)這個(gè)現(xiàn)象可以判斷改成員屬性是不是強(qiáng)引用

 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對(duì)象
3,Association關(guān)聯(lián)對(duì)象持有的強(qiáng)引用對(duì)象:通過fishhook,hook系統(tǒng)的api,自己存儲(chǔ)一份關(guān)聯(lián)對(duì)象的屬性map
4,普通的強(qiáng)引用對(duì)象:通過runtime的api那個(gè)他的屬性(class_copyIvarList)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Kotlin協(xié)程作用 Kotlin協(xié)程是一套基于Java Thread的線程框架,最大的特點(diǎn)就是可以1,用同...
    小紅軍storm閱讀 5,706評(píng)論 0 8
  • Run loops 是與 threads 關(guān)聯(lián)的基本基礎(chǔ)結(jié)構(gòu)的一部分。Run loop 是一個(gè) event pro...
    iOS三年閱讀 873評(píng)論 0 2
  • Block實(shí)際上是Objective-C對(duì)閉包的實(shí)現(xiàn)。 關(guān)于閉包的概念: In programming langu...
    chushen61閱讀 389評(píng)論 0 0
  • Block是什么? Block實(shí)際上是Objective-C對(duì)閉包的實(shí)現(xiàn)。 關(guān)于閉包的概念:In programm...
    Gekkko閱讀 1,650評(píng)論 0 12
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者,不喜歡去冒險(xiǎn),但是人生放棄了冒險(xiǎn),也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 7,560評(píng)論 0 4

友情鏈接更多精彩內(nèi)容