测试设备: iPhone 6真机
系统版本: iOS 12.0.1
检测工具: 腾讯的MLeaksFinder框架
场景:
从控制器A push到控制器B, B中包含UITextFiled控件, 再由B pop回A. 此时MLeaksFinder弹出内存泄漏提示框
确认问题:
调用dealloc方法, 发现控制器B确实销毁了. 但UITextFiled的dealloc方法却没有调用. 所以可以确认是UITextFiled引起的内存泄漏. 蛋疼的是, Xcode instruments检测不到该内存泄漏. 所以基本可以确定是苹果爸爸的bug了
经过查询, 发现UITextFiled引起内存泄漏的问题从iOS11.0就出现了, 于是尝试了网上的几种主流修复方式:
方案1: 创建分类, 通过私有属性textContentView拿到textField, 让textField从superView移除并设置为nil. (然并卵)
#import "UITextField+MemoryLeak.h"
@implementation UITextField (MemoryLeak)
- (void)removeFromSuperview {
if (@available(iOS 11.0, *)) {
id view = [self valueForKey:@"textContentView"];
if (view) {
[view removeFromSuperview];
[self setValue:nil forKey:@"textContentView"];
}
}
}
@end
方案2: 创建分类, 通过私有属性textContentView.provider拿到textField, 将textField设置为nil. (然并卵)
#import "UITextField+MemoryLeak.h"
@implementation UITextField (MemoryLeak)
- (void)didMoveToWindow{
[super didMoveToWindow];
if (@available(iOS 11.2, *)) {
NSString *keyPath = @"textContentView.provider";
@try {
if (self.window) {
id provider = [self valueForKeyPath:keyPath];
if (!provider && self) {
[self setValue:self forKeyPath:keyPath];
}
} else {
[self setValue:nil forKeyPath:keyPath];
}
} @catch (NSException *exception) {
NSLog(@"%@", exception);
}
}
}
@end
最后不得不尝试比较苟且的方式:
方式1: 按MLeaksFinder的log提示, 在UITextFiled分类中导入NSObject+MemoryLeak头文件, 重写-willDealloc方法, 屏蔽掉弹窗
#import "UITextField+MemoryLeak.h"
#import "NSObject+MemoryLeak.h"
@implementation UITextField (MemoryLeak)
- (BOOL)willDealloc {
return NO;
}
@end
方式2: 在 NSObject+MemoryLeak.m文件中, 将UITextFiled加入白名单. 省去创建分类的操作
+ (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"];
}
// 将UITextField加入白名单
if ([systemVersion compare:@"11.0" options:NSNumericSearch] != NSOrderedAscending) {
[whiteList addObject:@"UITextField"];
}
});
return whiteList;
}
参考:
https://www.jianshu.com/p/5add8d20f8a1
https://github.com/spicyShrimp/iOS11_UITextField_Fix
https://juejin.im/post/5a56c779f265da3e243b6c34
https://github.com/Tencent/MLeaksFinder/issues/80
https://forums.developer.apple.com/thread/94323