前言
[strongSelf assertNotDealloc];
是触发弹框的地方。调用它的方法是- (BOOL)willDealloc
.
- (BOOL)willDealloc {
NSString *className = NSStringFromClass([self class]);
if ([[NSObject classNamesInWhiteList] containsObject:className])
return NO;
NSNumber *senderPtr = objc_getAssociatedObject([UIApplication sharedApplication], kLatestSenderKey);
if ([senderPtr isEqualToNumber:@((uintptr_t)self)])
return NO;
__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong id strongSelf = weakSelf;
[strongSelf assertNotDealloc];
});
return YES;
}
简单分析一下,三种情况都可以导致不触发弹框执行。
-
[[NSObject classNamesInWhiteList] containsObject:className]
为True. -
[senderPtr isEqualToNumber:@((uintptr_t)self)]
为True. -
__strong id strongSelf = weakSelf;
中的strongify为nil.
白名单classNamesInWhiteList
创建一个NSMutableSet对象 whiteList
,不使用一个类方法,因为是一个配置列表,不需要每次重复创建,使用一个单例。在Set中的类型不监测内存泄漏
+ (NSSet *)classNamesInWhiteList {
static NSMutableSet *whiteList;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
whiteList = [NSMutableSet setWithObjects:
@"UIFieldEditor", // UIAlertControllerTextField
@"UINavigationBar",
@"_UIAlertControllerActionView",
@"_UIVisualEffectBackdropView",
nil];
// System's bug since iOS 10 and not fixed yet up to this ci.
NSString *systemVersion = [UIDevice currentDevice].systemVersion;
if ([systemVersion compare:@"10.0" options:NSNumericSearch] != NSOrderedAscending) {
[whiteList addObject:@"UISwitch"];
}
});
return whiteList;
}
根据self获取要监测的对象的类名名字。查看类的名字是否在白名单中。
如果在,退出,不会弹框。
NSString *className = NSStringFromClass([self class]);
if ([[NSObject classNamesInWhiteList] containsObject:className])
return NO;
正在执行target-Action
的target
对象不监测内存泄漏
当用户触发执行Target-Action
方法的时候,实际上在执行action
方法前,是
sender
对象先执行sendAction:to:forEvent
方法,然后UIApplicatoin执行
sendAction:to:from:forEvent:
方法,其中from
就是sender
对象.
这里使用方法交换截获sendAction:to:from:forEvent:
,然后截获了当前sender
对象保存在kLatestSenderKey
中
- (BOOL)swizzled_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event {
objc_setAssociatedObject(self, kLatestSenderKey, @((uintptr_t)sender), OBJC_ASSOCIATION_RETAIN);
return [self swizzled_sendAction:action to:target from:sender forEvent:event];
}
获取self
的地址转换为无符号整形,如果当前检测的对象是一个正在执行action方法的sender
那么,忽略不检测它的内存泄漏情况
NSNumber *senderPtr = objc_getAssociatedObject([UIApplication sharedApplication], kLatestSenderKey);
if ([senderPtr isEqualToNumber:@((uintptr_t)self)])
return NO;
延时后判断self
是否被释放
默认情况下,UIViewController在执行pop后([objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue]
为True后)的再调用Disappear接下来应该会被释放。开发者认为2秒内肯定会产生释放行为。如果被释放了,strongify
就为空,不会触发弹框。
网友评论