【问题标题】:SWIFT - UIImage(contentsOfFile: "") SLOWER than UIImage(imageLiteralResourceName: "") WHY?SWIFT - UIImage(contentsOfFile: "") 比 UIImage(imageLiteralResourceName: "") 慢 为什么?
【发布时间】:2019-01-29 10:59:39
【问题描述】:

遇到一个奇怪的问题,当 UIImage(contentsOfFile: "") SLOWER than UIImage(imageLiteralResourceName: "")

在我的 CALayer 中,我有一个全局变量

let img:UIImage? = nil

...如果 viewDidLoad 我正在使用“contentsOfFile”加载 img,那么它会非常缓慢地绘制此图像。 (例如在 touchMove+refresh CPU 低于 99-100% 和 FPS 5-10 期间)

img = UIImage(cgImage: UIImage(contentsOfFile: controlPath! + "/line.png")!.cgImage!, scale: 2.0, orientation: UIImage.Orientation.up)

但是...如果在 viewDidLoad 中我使用“imageLiteralResourceName”或 UIImage(data:NSDATA) 加载相同的 img - 那么它就完美了! CPU负载低,FPS40-60 为什么???

img = UIImage(cgImage: UIImage(imageLiteralResourceName: "line.png").cgImage!, scale: 2.0, orientation: UIImage.Orientation.up).cgImage

在屏幕上绘制此图像的 100 个副本的代码:

override public func draw(in ctx: CGContext) {
...

   //here we draw this image... nothing special
   for _ in 0...99{
      ctx.draw(img.cgImage!, in: randomPositionRect)
   }

...
}

刷新屏幕:

  override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesMoved(touches, with: event)
    ....

    myLayer.setNeedsDisplay()
}

PS> 在目标 c 中,它在两种情况下都能快速运行。仅与 SWIFT 相关的问题

完整的绘制代码:

var value = self.frame.size.height/2.0  //this value is changing in touchMove

override public func draw(in ctx: CGContext) {

    let height:CGFloat = self.frame.size.height-paddingTop!-paddingBottom!

    //rotate screen
    ctx.translateBy(x: +(frame.size.width / 2), y: +(frame.size.height / 2))
    ctx.rotate(by: degreesToRadians(x: 180))
    ctx.scaleBy(x: -1.0, y: 1.0)
    ctx.translateBy(x: -(frame.size.width / 2), y: -(frame.size.height / 2))

    ////
    ctx.translateBy(x: 0.0, y: 110)

    //Define the degrees needed for each plane to create a circle
    let degForPlane = Float(360.0 / CGFloat(panelsCount!))
    let radius: CGFloat = height / 2.0


    //The current angle offset (initially it is 0... it will change through the pan function)
    let vv: CGFloat = ((160.0 / frame.size.height) * (self.value)) + 10
    var degX: CGFloat = vv
    degX -= 90
    degX += 360

    /////DRAW Carousel ////

    let rect = CGRect(x: 0, y: 0 - (originalPanelSize!.height / 2.0), width: originalPanelSize!.width, height: originalPanelSize!.height)

    for i in 0...panelsCount!-1 {

        //Create the Matrix identity
        var t: CATransform3D = CATransform3DIdentity

        //Perform rotate on the matrix identity
        t = CATransform3DRotate(t, degreesToRadians(x: degX), 1.0, 0.0, 0.0)

        //Perform translate on the current transform matrix (identity + rotate)
        t = CATransform3DTranslate(t, 0.0, 0.0, radius)

        if i > -1 && ((degX >= -180 && degX <= 90) || (degX >= 270 && degX <= 450)) {
            let affine = CGAffineTransform(a: t.m11, b: t.m12, c: t.m21, d: t.m22, tx: t.m41, ty: t.m42)

            ctx.saveGState()
            ctx.concatenate(affine)


            ctx.draw(img!, in: rect)

            ctx.restoreGState()

        }

        degX -= CGFloat(degForPlane)

    }
}

【问题讨论】:

  • 请显示整个绘图代码。如果您在 draw 函数中加载图像,那么您做错了。也不需要访问CGImage 来绘制图像。另请注意,这两种方法不太可能加载相同的图像,因为contentsOfFile: 实际上不会以正确的比例加载图像。
  • 没问题。添加了完整的 ctx.draw 代码。我在 viewDidLoad() 中加载 img
  • UIImage(imageLiteralResourceName:) 和 UIImage(named:) 都在缓存加载的图像,因此第二次加载它们应该总是更快。
  • 有趣,到目前为止,我认为这两种方法没有区别。你有什么 Xcode 和 iOS 版本?

标签: swift performance uiimage cpu draw


【解决方案1】:

我目前的解决方案是使用通过 NSData 加载图像的自定义扩展:

创建文件UIImage+ext.swift

import Foundation
import UIKit

extension UIImage{

static func fromFile (path:String)->UIImage? {

    if let data = NSData(contentsOfFile: path) {
        return UIImage(cgImage: UIImage(data: data as Data)!.cgImage!, scale: UIScreen.main.scale, orientation: UIImage.Orientation.up)
    }

    return nil
}

}

用途:

let img = UIImage.fromFile(path: "MyFoler1/MyFolder2/File.png")

【讨论】:

  • 你为什么将UIImage转换为cgImage只是为了立即转换为UIImage?
  • 否则,视网膜屏幕上的图像看起来会很差。比例将是 1.0 而不是 2.0。
  • 您可以将比例设置为第二个参数:init(data:scale:)
  • 或者,您可以将@2x 添加到图像文件名中。或者将图像放到Assets.xcassets 并在那里设置它们的比例。
  • 什么?只需获取您拥有的文件并添加@2x。不要再添加 2 个文件,只需更改现有文件的名称。如果您在任何地方都指定scale: 2.0,那么它们肯定是@2x 图像。让系统知道它,而不是让它认为它是@1x,然后手动重新调整它。
猜你喜欢
  • 2016-10-14
  • 1970-01-01
  • 2016-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
相关资源
最近更新 更多