Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why UIFont(descriptor:size:) is x200 slower than UIFont(name:size:)?

Tags:

ios

iphone

Recently I noticed that the performance of a scroll was slowing down. I tracked down the problem, and I found that the cause was a the use of font created by the UIFont(descriptor:size:) constructor. I changed that constructor for UIFont(name:size:) and my problems were solved.

I isolated the problem in a project. The code is:

import UIKit

class ViewController: UIViewController {
  @IBOutlet weak var firstLabel: UILabel!
  @IBOutlet weak var secondLabel: UILabel!

  @IBAction func onStartTest(sender: AnyObject) {
    startMeasurement()
    let firstFont = UIFont(name: "Marker Felt", size: 16)
    firstLabel.font = firstFont
    finishMeasurement("UIFont(name)")

    startMeasurement()
    let secondFontDescriptor = UIFontDescriptor(name: "Marker Felt", size: 16)
    let secondFont = UIFont(descriptor: secondFontDescriptor, size: 16)
    secondLabel.font = secondFont
    finishMeasurement("UIFont(descriptor)")
  }
}

private var time: UInt64 = 0

public func startMeasurement() {
  time = mach_absolute_time()
}

public func finishMeasurement(name: String) {
  let duration = mach_absolute_time() - time
  print("* \(name) \(duration)ns")
}

These are some of my measurements:

iPhone 4S - iOS 9.0.2

* UIFont(name) 111,300ns
* UIFont(descriptor) 112,420,263ns

iPhone 6S - iOS iOS 9.2

* UIFont(name) 134,247ns
* UIFont(descriptor) 17,047,707ns

Simulator - iOS 9.2

* UIFont(name) 1,971,106ns
* UIFont(descriptor) 485,208,205ns

Simulator - iOS 8.1

* UIFont(name) 9,946,584ns
* UIFont(descriptor) 1,957,802,431ns

Am I doing something wrong?

like image 256
Alvivi Avatar asked Jan 22 '16 20:01

Alvivi


1 Answers

I asked an engineer at WWDC 2018, and he told me essentially this:

Descriptors are very very expensive because they are searching the ENTIRE system font library every single time for the characteristics you've provided. He told me that this search really isn't optimized and so should never be used in a scrolling situation and should really only be called once and then cached. It's doing this because you don't actually need to specify the font name but instead just various qualities of it and the system will provide you with something.

UIFont(name: size:) however is very fast because it's going directly to the requested font in the system. It knows where the font is because you have given the full exact name and it can then just scale it. No other nice features.

It's roughly an O(n) operation vs an O(1)

like image 132
Allison Avatar answered Oct 27 '22 10:10

Allison