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)