DoraemonKit部分功能核心原理解析

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

- (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庫拿到引用環(huán).

再說一下FBRetainCycleDetector原理:
簡單說,根據傳入的可能有引用循環(huán)的對象,深度遍歷所有持有的屬性,然后判斷是不是有換.主要分為如下幾類
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)

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末附帽,一起剝皮案震驚了整個濱河市库北,隨后出現的幾起案子毫别,更是在濱河造成了極大的恐慌,老刑警劉巖静袖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚪黑,死亡現場離奇詭異彻舰,居然都是意外死亡,警方通過查閱死者的電腦和手機诫咱,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門笙隙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坎缭,你說我怎么就攤上這事竟痰。” “怎么了掏呼?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵坏快,是天一觀的道長。 經常有香客問我憎夷,道長莽鸿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任拾给,我火速辦了婚禮祥得,結果婚禮上,老公的妹妹穿的比我還像新娘蒋得。我一直安慰自己级及,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布额衙。 她就那樣靜靜地躺著饮焦,像睡著了一般怕吴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上县踢,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天转绷,我揣著相機與錄音,去河邊找鬼殿雪。 笑死暇咆,一個胖子當著我的面吹牛,可吹牛的內容都是我干的丙曙。 我是一名探鬼主播爸业,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼亏镰!你這毒婦竟也來了扯旷?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤索抓,失蹤者是張志新(化名)和其女友劉穎钧忽,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體逼肯,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡耸黑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了篮幢。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片大刊。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖三椿,靈堂內的尸體忽然破棺而出缺菌,到底是詐尸還是另有隱情,我是刑警寧澤搜锰,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布伴郁,位于F島的核電站,受9級特大地震影響蛋叼,放射性物質發(fā)生泄漏焊傅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一鸦列、第九天 我趴在偏房一處隱蔽的房頂上張望租冠。 院中可真熱鬧,春花似錦薯嗤、人聲如沸顽爹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镜粤。三九已至捏题,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肉渴,已是汗流浹背公荧。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留同规,地道東北人循狰。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像券勺,于是被迫代替她去往敵國和親绪钥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容

  • 1. Kotlin協程作用 Kotlin協程是一套基于Java Thread的線程框架关炼,最大的特點就是可以1程腹,用同...
    小紅軍storm閱讀 5,346評論 0 8
  • Run loops 是與 threads 關聯的基本基礎結構的一部分。Run loop 是一個 event pro...
    iOS三年閱讀 547評論 0 2
  • Block實際上是Objective-C對閉包的實現儒拂。 關于閉包的概念: In programming langu...
    chushen61閱讀 347評論 0 0
  • Block是什么寸潦? Block實際上是Objective-C對閉包的實現。 關于閉包的概念:In programm...
    Gekkko閱讀 1,449評論 0 12
  • 16宿命:用概率思維提高你的勝算 以前的我是風險厭惡者社痛,不喜歡去冒險见转,但是人生放棄了冒險,也就放棄了無數的可能蒜哀。 ...
    yichen大刀閱讀 6,049評論 0 4