美文网首页iOS 开发
UITextFiled的内存泄漏问题

UITextFiled的内存泄漏问题

作者: 自负的大撸sir | 来源:发表于2018-11-07 18:05 被阅读95次

    测试设备: iPhone 6真机
    系统版本: iOS 12.0.1
    检测工具: 腾讯的MLeaksFinder框架

    场景:

    从控制器A push到控制器B, B中包含UITextFiled控件, 再由B pop回A. 此时MLeaksFinder弹出内存泄漏提示框


    ml截图.png

    确认问题:

    调用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

    相关文章

      网友评论

        本文标题:UITextFiled的内存泄漏问题

        本文链接:https://www.haomeiwen.com/subject/wonvxqtx.html