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)