进击的Bug---那些年我遇到的大坑5(循环引用导致内存泄露)

发表于 2016-09-29 21:27 显示全部楼层 19 3473


功能: 控制器销毁时,在dealloc方法中注销通知

bug:偶尔会出现循环引用,导致dealloc方法不调用,通知无法移除,出现bug;


作为一名老司机,遇到循环引用并不紧张,首先对最常见的三种情况进行了排除:

  1. 计时器NSTimer未正确销毁,没有调用invalidate并置nil;

  2. 代理属性使用了strong而不是weak;

  3. block里面没有使用__weak修饰;


然而,经过认真检查比对,发现并不存在以上三种情况,但内存泄露仍然时有发生,这下麻烦了

尝试用leaks工具来调试,明明dealloc方法没调用,竟然检测不到内存泄露?!!!!这下真的不好搞了

instrument.png    leaks.png


然后只好对调用的方法逐一注释,慢慢测试,

最后终于发现问题就出在输入按钮上,

只要点击了这个按钮就会出现循环引用,不点击就一切正常,代码:

//输入按钮
    UIButton *inputButton = [[UIButton alloc] init];
    [self.allInfoView addSubview:inputButton];
    [inputButton mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(bottomBackgroundImageView);
        make.left.equalTo(checkGrabSeatAudienceButton.mas_right).offset(10);
        make.right.equalTo(grabSeatButton.mas_left).offset(-5);
        make.bottom.equalTo(bottomBackgroundImageView);
    }];
    [inputButton setTitle:@"跟主播说点什么" forState:UIControlStateNormal];

//按钮点击显示输入框,这里用的是BlocksKit框架
    @weakify(self)//解决循环引用
    [inputButton bk_addEventHandler:^(id sender) {
        @strongify(self)
        [self showInputView];
    } forControlEvents:UIControlEventTouchUpInside];
    
//这里的block看上去没有问题啊,继续深入研究[self showInputView]方法



找到显示输入框的这个方法,这是一个第三方键盘的示例代码,直接拿过来的

事实证明抄别人的代码真是害死人啊,别人的成员变量都是这么定义的

//直接定义了成员变量
@interface AudienceStudioViewController ()
{
    GrowingInputView *_growingInputView;//输入框
    BOOL _showKeyBoard;
    NSInteger _keyboardHeight;
    BOOL _keyboardVisible;
    BOOL _canResetGrowingInputView;
}

@end
//调用方法实现,没有用self.来调用
@implementation AudienceStudioViewController
//展示输入框
- (void)showInputView {
    if (_growingInputView == nil) {//输入框懒加载
        _growingInputView = [[GrowingInputView alloc] initWithFrame:CGRectZero];
        _growingInputView.frame = CGRectMake(0, self.view.height - [GrowingInputView defaultHeight], self.view.width, [GrowingInputView defaultHeight]);
        _growingInputView.placeholder = @"我来说点什么吧~";
        _growingInputView.delegate = self;
        _growingInputView.parentView = self.view;
        
        [self.allInfoView addSubview:_growingInputView];
    }
    _growingInputView.hidden = NO;
    
    //让组件内部的textView成为第一响应者
    [_growingInputView activateInput];
    
    /***************************/
    //这里直接使用下划线的成员变量,没有使用self.的getter方法,于是造成了在block中调用时循环引用,而且是使用了输入法之后才会内存泄露,不点击输入按钮就没有内存泄露
}


@end




解决方法:定义属性时,使用weak属性修饰符,在block中调用时,用self.方式来调用

@property (weak, nonatomic) GrowingInputView *growingInputView;//输入框
@property (assign, nonatomic) BOOL showKeyBoard;
@property (assign, nonatomic) NSInteger keyboardHeight;
@property (assign, nonatomic) BOOL keyboardVisible;
@property (assign, nonatomic) BOOL canResetGrowingInputView;
//展示输入框
- (void)showInputView {
    if (self.growingInputView == nil) {//输入框懒加载
        GrowingInputView *growingInputView = [[GrowingInputView alloc] initWithFrame:CGRectZero];
        self.growingInputView  = growingInputView;
        self.growingInputView.frame = CGRectMake(0, self.view.height - [GrowingInputView defaultHeight], self.view.width, [GrowingInputView defaultHeight]);
        self.growingInputView.placeholder = @"我来说点什么吧~";
        self.growingInputView.delegate = self;
        self.growingInputView.parentView = self.view;
        
        [self.allInfoView addSubview:self.growingInputView];
    }
    self.growingInputView.hidden = NO;

    //让组件内部的textView成为第一响应者
    [self.growingInputView activateInput];
    
}



这下问题终于解决了,顺便说下,看来leak工具也不是万能的,明明有内存泄露也有检测不出来的时候

ps:抄别人代码时,一定要多想想.....

回复 使用道具
举报
纯银

发表于 2017-02-16 12:58 显示全部楼层

回复 支持 反对 使用道具
举报
寻找皮卡丘

发表于 2017-02-16 03:09 显示全部楼层

以诚感人者,人亦诚而应。一点回复,敬请笑纳!

回复 支持 反对 使用道具
举报
纯银

发表于 2017-02-15 16:17 显示全部楼层

回复 支持 反对 使用道具
举报
biubiuamy

发表于 2017-02-15 05:13 显示全部楼层

回复 支持 反对 使用道具
举报
随手拾起

发表于 2017-02-15 01:25 显示全部楼层

回复 支持 反对 使用道具
举报
踮脚怪

发表于 2017-02-14 11:43 显示全部楼层

回复 支持 反对 使用道具
举报
孵梦Reve

发表于 2017-02-14 03:28 显示全部楼层

回复 支持 反对 使用道具
举报
陈小呆

发表于 2017-02-13 19:32 显示全部楼层

回复 支持 反对 使用道具
举报
活泼的方小闹

发表于 2017-02-13 18:05 显示全部楼层

回复 支持 反对 使用道具
举报
12下一页

发表新文章
CoderXu

叩丁狼骨干成员

0

学分

1376

学币

2441

积分

叩丁狼骨干成员

Rank: 6Rank: 6

积分
2441

签到之王勋章叩丁狼一周年勋章活动达人勋章前100注册用户勋章叩丁狼iOS学员勋章论坛百帖达成勋章真土豪勋章勋章签到周冠军勋章签到月冠军勋章关注叩丁狼教育公众号意见领袖勋章叩丁狼周年庆杯子叩丁狼周年庆纪念勋章叩丁狼周年庆T恤关注新浪微博论坛荣誉内测勋章

Ta的主页 发消息
精华帖排行榜

精彩推荐

  • 关注叩丁狼教育