Tencent / QMUI_iOS

QMUI iOS——致力于提高项目 UI 开发效率的解决方案
http://qmuiteam.com/ios
Other
7.07k stars 1.37k forks source link

反馈一个问题,会导致程序卡死 #1270

Closed LisonFan closed 3 years ago

LisonFan commented 3 years ago

Bug 表现 程序卡死,不过不确定是在那处死循环了, 在公司项目中,通过 Instruments 分析发现是 QMUIRuntimeExtendImplementationOfVoidMethodWithoutArguments 但是在下面提供的 demo 中,Instruments 显示卡在了 image

视频 从视频中可以看出,点击后 CPU 占用持续 100%,并且内存持续增长 https://user-images.githubusercontent.com/9424775/126048769-ca2c4732-f2bf-4a14-843c-fe480f77bfbb.mp4

如何重现 一段能复现问题的代码

#import <MyLayout/MyLayout.h>
#import <QMUIKit/QMUIKit.h>
#import <Masonry/Masonry.h>

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = UIColor.whiteColor;

    MyLinearLayout *layout = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Vert];
    layout.myHorzMargin = 0;
    layout.myHeight = MyLayoutSize.wrap;
    [self.view addSubview:layout];
    [layout mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
    }];
    for (int i = 0; i < 10; i++) {
        QMUIButton *btn = QMUIButton.new;
        [btn setTitle:@"asdasd" forState:UIControlStateNormal];
        [btn sizeToFit];
        [layout addSubview:btn];
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [QMUITips showLoading:nil inView:self.view];
}

其他信息

MoLice commented 3 years ago

4.1.3 版本太老,一般不会再去查了。

当你卡死时点 Xcode 的暂停按钮就可以看到当前正在执行什么了。

LisonFan commented 3 years ago

4.1.3 版本太老,一般不会再去查了。

当你卡死时点 Xcode 的暂停按钮就可以看到当前正在执行什么了。

刚更新到 4.2.3 最新版本也是同样能复现,暂停后如下图,看上去是 MyLayout 和 QMUIKit 冲突了? 这张图我是将 QMUIButton 换成 UIButton 后的信息 image

这张是用的 QMUIButton image

ExtendImplementationOfVoidMethodWithoutArguments 加了个输出

https://user-images.githubusercontent.com/9424775/126049796-567c9cc7-7a6e-4d86-874f-801dfb922212.mp4

MoLice commented 3 years ago

好,提供一份Demo来调试吧

LisonFan commented 3 years ago

好,提供一份Demo来调试吧

Demo.zip

麻烦了

MoLice commented 3 years ago

你的 issue 障眼法太多了,建议遇到问题自行排除无关的代码。

例如你所谓的“卡死”是因为你在 ViewController 的 touchBegan 里试图显示 QMUITips:

而这段代码放在 touchBegan 里就很奇怪:Demo 跑起来后我不点击界面,是不知道是否卡死的,但一点击,就会运行你这个,就会导致卡死。

卡死的原因是因为 QMUITips 是 UIWindow 实现的,而你的项目使用了 UIScene,目前 QMUI 不支持 UIScene,具体可参考 #766。试图显示 UIWindow 时会不断触发 MyBaseLayout 的 layoutSubviews。

去掉 touchBegan 这段代码其实就正常了,但你可以发现按钮无法点击,因为你的 MyLinearLayout 并没有给它指定布局宽度,最终 MyLinearLayout 的宽度为 0,内部的 subviews 都无法接受点击事件。这个和用了 QMUI 没关系,和 UIButton 还是 QMUIButton 也没关系。

所以最终你的 Demo 只需要存在 MyLinearLayout 和 QMUITips 就好了,其他代码全都是障眼法,在提供 Demo 前应该自行通过注释代码来排除不相关的条件。