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)