如何优化iOS系统上的图文评论UI界面

在我的社交 APP 上,⽤户动态由精美的照视频成。于每视频, 我 展示出完整的标题和五最新评论由于⽤户使⽤标题来讲述照背后的故事, 因此它们通常很 、很复杂 且可能包含超 接和表情符渲染如此复杂带来问题 滚动时造成性能下降。 

即使在 iPhone 12 这样的新设备上, 复杂标题的初始制需要⻓达 50 毫秒, ⽽⽂本展示 需要⻓达 30 毫秒, 渲染速度很慢。问题还简单问题 需要加更加复杂图⽚⾄视频所有些步发⽣在 UI 线程上, 致app在⽤户滚动时丢帧

基础知识:

始之前, 最好先了解本的基本念。

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

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

2. 更新 UI

线程必须处理太多操作 最常的后果是出现丢帧现象, 不能保 60 fps (每 16.67 毫秒 会发⽣这种现象。

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

很容易发现帧问题 最常的表形式是⽆响应/

可以使友盟+ U-APM iPhone12 这样的新款设备上是否会发⽣

如何优化iOS系统上的图文评论UI界面

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

使 CADisplayLink

class DroppingFramesHelper: NSObject {

private var firstTime: TimeInterval = 0.0

private var lastTime: TimeInterval = 0.0

func activate() {

let link = CADisplayLink(target: self, selector: #selector(updat

link.add(to: .main, forMode: .commonModes)

}

@objc private func update(link: CADisplayLink) {

if lastTime == 0 {

firstTime = link.timestamp

lastTime = link.timestamp

}

let currentTime = link.timestamp

let elapsedTime = floor((currentTime - lastTime) * 10_000)/10

let totalElapsedTime = currentTime - firstTime

if elapsedTime > 16.7 {

print("[DFH] Frame was dropped with elpased time of \(elapse

}

lastTime = link.timestamp

}

}


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

didFinishLaunchingWithOptionsDroppingFramesHelper().activate()

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

如何优化iOS系统上的图文评论UI界面

采取的措施

在通控制台和友盟+ U-APM知道了掉的情存在, 能做些什呢? 可以采取些下⾯这些措施:

(1) 视图和透明视图

(2) 化“连续调⽤中的负载

(3) JPEG

(4) 渲染

 们将会⼀⼀进⾏讨论

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

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

  视图

  降低透明度

法很简单

label.layer.opacity = 1.0

label.backgroundColor = .white

了更加容易地察到重的透明度, 可以使 ⼀个⾮便的具:  调试-> 视图调试 - > 渲染 ->颜⾊混合

这个⼯可以松地发现视图, 如下所示:

如何优化iOS系统上的图文评论UI界面

在我不需要 这⾥使⽤标签将背景颜⾊设晰。

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

显⽽ cellForItemAt indexPath scrollViewDidScroll 这样连续调⽤的函须运算得常快。

所以我们尽可能使最“单纯视图/元格, 使⽤⾮巧快速的法。 (例如, 不涉及布局束、象分配的配置)

3.解码JPEG图像

们处丢帧问题时 的“可化点”是像解

通常, 这个操作是在主线程上是由 imageViews 完成的, 但在会导致我应⽤程序慢。

这个问题 ⼀种决⽅案是码⼯作移后台列。这样 操作不UIImageView 的正常解样⾼效, mainThread 是空的。

 在后台解码图像:

extension UIImage {

class func decodedImage(_ image: UIImage) -> UIImage? {

guard let newImage = image.cgImage else { return nil }


 // To optimize this, you can some cache control.

let colorspace = CGColorSpaceCreateDeviceRGB()

let context = CGContext(data: nil,

width: newImage.width,

height: newImage.height,

bitsPerComponent: 8,

bytesPerRow: newImage.width * 4,

space: colorspace,

bitmapInfo: CGImageAlphaInfo.noneSkipFir

context?.draw(newImage, in: CGRect(x: 0, y: 0, width: newImage.w

let drawnImage = context?.makeImage()

if let drawnImage = drawnImage {

return UIImage(cgImage: drawnImage)

}

return nil

}

}

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


import UIKit

class AsyncImageView: UIView {

private var _image: UIImage?

var image: UIImage? {

get {

return _image

}

set {

_image = newValue

layer.contents = nil

guard let image = newValue else { return }

DispatchQueue.global(qos: .userInitiated).async {

DispatchQueue.main.sync { }

let decodedImage = UIImage.decodedImage(image)

DispatchQueue.main.async {

self.layer.contents = decodedImage?.cgImage

}

}

}

}

可以使“AsyncImageView”, 在后台线不是主线程中解码图像。

为什么使用DispatchQueue.main.sync{}?

debug 的前期我们尝试不使sync 但是程序发⽣了崩溃⾏为了找出原因, 使 友盟+ U-APM 检测进⾏测试

如何优化iOS系统上的图文评论UI界面

可以从图中看出, 码导致了 OOM 警, 是由于存警告是在主线程上理的,   正在后台像, 所以如果我使太多存, 就意外⾏为并带来极⼤⻛险 (例发⽣的崩

4.离屏渲染

们处 UI 元素的特定 可能遇到些离渲染问题 需要在呈现它们 前准渲染些元素。意味着量使 CPU GPU

如何发现这种问题?

使具:  Debug -> View Debugging -> Rendering -> Color Oscreen-Rendered Yellow和前点的例相似, 使具, 我可以发现⻩⾊红⾊突出示的元素。

以下代码内容:

imageView.layer.cornerRadius = avatarImageHeight / 2.0

使  UIBezierPath 代替, 可以简单地解特定的离渲染问题

extension UIImage {

class func circularImage(from image: UIImage, size: CGSize)

let scale = UIScreen.main.scale

let circleRect = CGRect(x: 0, y: 0, width: size.width *

 

UIGraphicsBeginImageContextWithOptions(circleRect.size,

 

-> UIImage? {

 

scale, height:

 

false, scale)

let circlePath = UIBezierPath(roundedRect: circleRect, cornerRadius: c

circlePath.addClip()

 

image.draw(in: circleRect)

 

if let roundImage = UIGraphicsGetImageFromCurrentImageContext() {

return roundImage

}

 

return nil

}

}


简而言之,以下是通过调试得出的几点经验:

1.避免CornerRadius属性:

2. 避免使 ShouldRasterize

3. 使  .rounded() 更容易算。

4. Shadows 会导致离渲染。

其他经验:

可以尝试⼀下以下的化建

1. (boudingRectWithSize 但是 debug 程可能常繁重。 ⾮⾮常需要, 请尽量避免使⽤它们

2. 检查结构布局, 尤其是使⽤⾃动布局且必须⽀旧设备时

3. 尝试将⼯作放后台列, 但注意存警告。



作者:郑文韬

上一篇:高校学生在家实践ECS弹性云服务器


下一篇:计算linux系统资源的简单脚本