iOS13卡顿问题(四)规避重用

这一篇过了快三个月才输出,从这个时间跨度就可以看出来,这个问题确实很棘手。但是,这一次我们终于有了重点突破。先看看结论:

Image

在版本上线后,我们的全版本卡顿趋势持续下降,稳定后和之前相比,1s阈值的卡顿下降了1%左右。从数据上看到,这次的尝试和之前相比,的确有了明显的效果。

接下来,我们说说,具体做了哪些分析和操作。

在上一篇中,我们已经得出结论,iOS13的卡顿依然收敛到页面当中来,主要集中在以下几个页面:

  1. 首页

  2. 练习完成页

  3. 计划详情页

  4. 练习中途退出页

集中分析这几个页面,以及结合之前得出的结论来看,这几个页面有几个比较值得讨论的共性:

  1. 使用UITableView

  2. 几乎都是独立Cell,重用机制实际没有启用

在不需要使用重用,但是使用UITableView就总会尝试进行Cell的复用检查,以及不必要的cell创建。

所以,针对不需要重用的列表,我们习惯使用UITableView相关API操作UI的场景,着手准备以下两种方案进行尝试:

  1. 使用UIScrollView手动布局,手动维护列表排版

  2. 依然使用UITableView,但是完全不调用dequeueReusableCellWithReuseIdentifier等和重用机制相关的API,直接使用懒加载或者其他方式生成相关cell然后return

随着产品有重构首页的需求,采取了第一种方式,使用UIScrollView手动管理列表,来实现一个完全没有重用机制的列表。

接下来,我们看看已经实现后的UI层级:

Image

尽量保证不要有过多的UI层级,所以几乎所有的卡片都是直接贴在UIScrollView上。

具体代码的结构如下:

  1. UIScrollView用来承载列表

  2. 每一个卡片都是一个单独的类

  3. 初始化各个卡片,以及整体排版

  4. 手动更新卡片排版

Image

这里,我们重点看一下,手动更新卡片排版的代码:

// 首页各个模块的位置索引typedef NS_ENUM (NSInteger, YGScheduleRootViewIndex) {    YGScheduleRootViewIndexFirst     = 0, //第一个下标    YGScheduleRootViewIndexBanner    = 0, //运营Banner的位置    YGScheduleRootViewIndexStatictis = 1, //练习数据的位置    YGScheduleRootViewIndexCalendar  = 2, //日历的位置    YGScheduleRootViewIndexDay       = 3, //单日安排的位置    YGScheduleRootViewIndexActivity  = 4, //运营活动的位置    YGScheduleRootViewIndexSessions  = 5, //参加课程的位置    YGScheduleRootViewIndexBottomBtn = 6, //底部按钮的位置    YGScheduleRootViewIndexLast      = 7, //最后一个下标};- (void)updateAllView {    for (NSInteger i = YGScheduleRootViewIndexCalendar; i < YGScheduleRootViewIndexLast; i++) {        UIView *subView = [self subViewWithIndex:i];        [subView.layer removeAllAnimations];    }    [UIView animateWithDuration:0.3 animations:^{        CGFloat top = 0;        CGFloat bottom = 0;        for (NSInteger i = YGScheduleRootViewIndexFirst; i < YGScheduleRootViewIndexLast; i++) {            UIView *subView = [self subViewWithIndex:i];            if (subView) {                if (i == YGScheduleRootViewIndexBanner                    || i == YGScheduleRootViewIndexStatictis                    || i == YGScheduleRootViewIndexDay) {                    subView.top = top;                } else if (i == YGScheduleRootViewIndexBottomBtn) {                    subView.top = top + 24;                } else {                    subView.top = top + 16;                }                top = subView.bottom;                bottom = subView.bottom;            }        }        self.lastViewBottom = bottom;        if ((_trialView.superview             && !_trialView.hidden)            || (_proExpireRemindView.superview                && !_proExpireRemindView.hidden)) {            [self.mainScollView setContentSize:CGSizeMake(self.mainScollView.width, self.lastViewBottom + 100)];        } else {            [self.mainScollView setContentSize:CGSizeMake(self.mainScollView.width, self.lastViewBottom + 50)];        }    }];}

由于依然不知道iOS在这个卡顿实际的内部的渲染机制,所以方法一做了尝试上线让数据来说话,现实证明了终于找到一个切实可行的方案去解决这个问题。

但是,方法一的弊端是代码过于松散,要么自己抽离一套API方便外部使用来管理UI,要么,还需要尝试一下方法二。

所以,接下来的工作准备着手,针对练习完成页面进行方法一和方法二的ABTest测试。同时,进行方法一的控件封装。

Let’s think!

你可能感兴趣的:(iOS13卡顿问题(四)规避重用)