借助友盟+U-APM实现如何优化ios系统上的图文评论UI界面

112 阅读5分钟

在我们的社交 APP 上, ⽤户的动态由精美的照⽚ 、视频和⽂字组成。对于每张照⽚和视频, 我 们都会展示出完整的标题和五个最新评论。 

由于⽤户喜欢使⽤标题来讲述照⽚背后的故事, 因此它们通常很⻓ 、很复杂, 并且可能包含超链 接和表情符号。

渲染如此复杂的⽂本带来了⼀些问题, 它在滚动时造成性能下降。

即使在 iPhone 12 这样的新设备上, 复杂标题的初始⽂本绘制需要⻓达 50 毫秒, ⽽⽂本展示 需要⻓达 30 毫秒, 渲染速度很慢。

⽂本问题还是简单问题, 有时我们需要加载更加复杂的图⽚甚⾄视频。

所有这些步骤都发⽣在 UI 线程上, 导致app在⽤户滚动时丢帧。

基础知识

在开始之前, 最好先了解本⽂的基本概念。

主线程不应该⽤于繁重的操作, ⽽主要⽤于:

  1. 接受⽤户输⼊/交互;

  2. 显示结果并更新 UI。

当主线程必须处理太多操作时, 最常⻅的后果是出现丢帧现象, 当我们不能保证 60 fps (每 16.67 毫秒⼀ 帧) 时就会发⽣这种现象。

精确地识别并调试丢帧问题

有时我们很容易发现掉帧问题, 因为掉帧最常⻅的表现形式是⽆响应/卡顿。

  我们可以使⽤友盟+ U-APM检查在 iPhone12 这样的新款设备上是否会发⽣卡顿。

1.jpg

显⽽易⻅在 iPhone12 上也发⽣了卡顿, 由此推断我们的代码存在优化空间, ⽽并⾮⽤户的设备 配置问题 。接下来, 我们需要更准确的⽅法来跟踪卡顿问题 。我们尝试了使⽤ CADisplayLink    和 TimeProfiler。

使⽤ CADisplayLink 类:

哦.jpg 然后, 在AppDelegate的⽅法中访问它的⼀个实例:

didFinishLaunchingWithOptions:DroppingFramesHelper().activate()

现在,如果测试程序出现丢帧的情况,我们可以在控制台上监控它们:

2.jpg

采取的措施

现在通过控制台和友盟+ U-APM知道了掉帧的情况存在, 我们能做些什么呢? 可以采取⼀些下

⾯这些措施:

(1) 减少视图和透明视图的数量

(2) 最⼩化“连续调⽤函数”中的负载

(3) 解码 JPEG 图像

(4) 离屏渲染

我们将会⼀⼀进⾏讨论。

1.减少试图和透明试图的数量

为了提⾼应⽤程序的性能, ⾸先要做的事是:

•  减少视图的数量。

•  降低透明度。

解决的⽅法很简单:

label.layer.opacity = 1.0
label.backgroundColor = .white
为了更加容易地观察到重叠的透明度, 我们可以使⽤ ⼀个⾮常⽅便的⼯具:  调试 -> 视图调试 - > 渲染 ->颜⾊混合层。
这个⼯具让我们可以轻松地发现重叠的视图, 如下图所示:

3.jpg 在我们不需要时, 这⾥使⽤标签将背景颜⾊设置为不清晰。

2.最小化“连续调用函数”中的负载

显⽽易⻅, 像 cellForItemAt indexPath 或 scrollViewDidScroll 这样被连续调⽤的函数必须运

算得⾮常快。

所以我们尽可能使⽤最“单纯”的视图/单元格, 并使⽤⾮常轻巧快速的运算⽅法。 (例如, 不涉

及布局约束、对象分配的配置)

3.解码JPEG图像

当我们处理丢帧问题时, 常⻅的“可优化点”是图像解码。

通常, 这个操作是在主线程上是由 imageViews 完成的, 但在图像⾮常⼤的时候会导致我们的 应⽤程序变慢。

为了缓解这个问题, ⼀种解决⽅案是将解码⼯作移⾄后台队列。这样, 操作不会像

UIImageView 采⽤的正常解码那样⾼效, 但 mainThread 将是空闲的。

在后台解码图像:

哦2.jpg

哦3.jpg

可以添加⼀些进⼀步的缓存控制以提⾼效率:

哦4.jpg 可以使⽤“AsyncImageView”, 在后台线程⽽不是主线程中解码图像。 为什么使⽤ DispatchQueue.main.sync { }? 在 debug 的前期我们尝试不使⽤ sync,但是程序发⽣了崩溃⾏为。为了找出原因,我们使⽤了友盟+ U-APM 的异常检测进⾏测试。

4.jpg

可以从图中看出,代码导致了 OOM 内存异常报警,这是由于内存警告是在主线程上处理的, ⽽我们正在后台处理图像,所以如果我们使⽤太多内存,就会出现意外⾏为并带来极⼤⻛险(例 如图中发⽣的崩溃)

4. 离屏渲染

当我们处理 UI 元素的特定属性时,可能会遇到⼀些离屏渲染问题,因为我们需要在呈现它们之 前准备渲染这些元素。这意味着⼤量使⽤ CPU 和 GPU。

如何发现这个问题?

我们使⽤了⼯具:Debug -> View Debugging -> Rendering -> Color Offscreen-Rendered Yellow。 和前⽂第⼆点的例⼦相似,使⽤此⼯具,我们可以发现以⻩⾊或红⾊突出显示的元素。

以下代码内容:

imageView.layer.cornerRadius = avatarImageHeight / 2.0

我们使⽤ UIBezierPath 代替,它可以简单地解决特定的离屏渲染问题:

哦5.jpg

简⽽⾔之,以下是通过调试得出的⼏点经验:

  1. 避免 CornerRadius 属性;
  2. 避免使⽤ ShouldRasterize;
  3. 使⽤ .rounded() 值,因为更容易计算。
  4. Shadows 也会导致离屏渲染。 其他建议 读者还可以尝试⼀下以下的优化建议:
  5. ⽂本测量(boudingRectWithSize),但是 debug 过程可能⾮常繁重。除⾮⾮常需要,否则 请尽量避免使⽤它们。
  6. 检查结构布局,尤其是使⽤⾃动布局并且必须⽀持旧设备时。
  7. 尝试将⼯作放⼊后台队列,但请注意内存警告。

本⽂出⾃于“「2021 友盟+ 移动应⽤性能挑战赛」” 中的参赛作品,该⽂章表述了作者如何借 助友盟+ U-APM⼯具进⾏了性能优化。

作者:郑文韬