Home iOS & Swift Books Auto Layout by Tutorials

15
Optimizing Auto Layout Performance Written by Jayven Nhan

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

App performance is critical for delivering a great end-user experience. A sluggish and unresponsive app tends to frustrate its users to the point where they delete the app. On the other hand, a fast and responsive app helps its users achieve their core tasks.

With Auto Layout, you have some handy tools available at your disposal to help fine-tune your app’s performance. In this chapter, you’ll learn about the following Auto Layout performance optimization topics:

  • Betting safe on performance with Interface Builder.
  • Factoring in the render loop.
  • Understanding constraints churning.
  • Utilizing static and dynamic constraints.
  • Batching and updating constraint changes.
  • Understanding the cost of using Auto Layout.
  • Making performance gains using best practices.

Betting safe on performance with Interface Builder

One of the benefits of using Interface Builder is that it reduces the room for errors when handling Auto Layout constraints. You show Interface Builder how you want your layout to look using constraints, and you put the rest into the hands of Apple.

In other words, Interface Builder handles the behind-the-scenes code.

However, many of today’s production apps implement Auto Layout partially or entirely using code. When you implement Auto Layout programmatically, you allow for greater customization — but you do so at the cost of widening the error margin for performance degradation. In short: The more you’re able to do, the more things can go wrong.

When using code for Auto Layout, it’s not only important to know what to do. It’s also important to know what not to do. For example, overriding and adding suboptimal code in updateConstraints() can cause disastrous performance or even a crash.

So, what’s better? It all depends. If you want Apple’s “it just works” experience with regard to optimizing Auto Layout performance, then use Interface Builder. If, however, you want finer control over how your Auto Layout is implemented, then the programmatic approach has more merit.

Factoring in the render loop

The render loop is not often talked about, yet it’s the backbone for laying out your user interface at every frame. Understanding how the render loop works will help you see the larger picture of how Auto Layout works with other system components. At the core, the render loop’s purpose is to ensure all of your views are presented as intended for every frame.

Why update constraints

As introduced earlier, making use of updateConstraints() can be a recipe for disaster. So, why use it? The title of this chapter may give it away: It’s for performance. There are two ways to make constraint changes when using code: in place or in batches by using updateConstraints().

Constraints churn

Constraints churn happens when constraints are repeatedly added and removed. Although this may not happen frequently, it’s essential to know what it looks like to avoid any misstep.

// 1
contentView.subviews.forEach { $0.removeFromSuperview() }
// 2
contentView.addSubview(usernameLabel)
contentView.addSubview(titleLabel)
contentView.addSubview(profileImageView)
contentView.addSubview(badgeImageView)
contentView.addSubview(descriptionLabel)
contentView.addSubview(postImageView)
contentView.addSubview(cakeImageView)
contentView.addSubview(isHighCalorieLabel)
// 3
NSLayoutConstraint.deactivate(layoutConstraints)
// 4
layoutConstraints =
  usernameLabelConstraints
  + titleLabelConstraints
  + profileConstraints
  + descriptionLabelConstraints
  + postImageViewConstraints
// 5
if beverage?.isHighCalorie ?? false {
  layoutConstraints += highCalorieConstraints
} else {
  layoutConstraints += lowCalorieConstraints
}
// 6
if beverage?.isFrequentUser ?? false {
  layoutConstraints += badgeImageViewConstraints
}
// 7
NSLayoutConstraint.activate(layoutConstraints)

Adding and removing subviews

Notably, there’s no need to add and remove subviews constantly. Instead, you only need to do this once when the view initializes.

contentView.subviews.forEach { $0.removeFromSuperview() }
contentView.addSubview(usernameLabel)
contentView.addSubview(titleLabel)
contentView.addSubview(profileImageView)
contentView.addSubview(badgeImageView)
contentView.addSubview(descriptionLabel)
contentView.addSubview(postImageView)
contentView.addSubview(cakeImageView)
contentView.addSubview(isHighCalorieLabel)

Activating and deactivating static constraints

Most of the constraints are static constraints, which don’t change throughout the lifetime of the view. They are there for good as long as the view doesn’t get deallocated. For static constraints, you need to ensure that they’re only going to activate once.

private var staticConstraints: [NSLayoutConstraint] = []
NSLayoutConstraint.deactivate(layoutConstraints)
layoutConstraints =
  usernameLabelConstraints
  + titleLabelConstraints
  + profileConstraints
  + descriptionLabelConstraints
  + postImageViewConstraints
if staticConstraints.isEmpty {
  staticConstraints =
    usernameLabelConstraints
    + titleLabelConstraints
    + profileConstraints
    + descriptionLabelConstraints
    + postImageViewConstraints
  NSLayoutConstraint.activate(staticConstraints)
}

Activating and deactivating dynamic constraints

Dynamic constraints are constraints that may change throughout the lifetime of a view. Part of the table view cell’s layout is dependent on the beverage properties.

private var dynamicConstraints: [NSLayoutConstraint] = []
private func updateDynamicConstraints(isHighCalorie: Bool) {
  NSLayoutConstraint.deactivate(dynamicConstraints)
  dynamicConstraints = isHighCalorie
    ? highCalorieConstraints : lowCalorieConstraints
  NSLayoutConstraint.activate(dynamicConstraints)
}
if beverage?.isHighCalorie ?? false {
  layoutConstraints += highCalorieConstraints
} else {
  layoutConstraints += lowCalorieConstraints
}
// 1
if beverage?.isHighCalorie ?? false
  && dynamicConstraints != highCalorieConstraints {
  updateDynamicConstraints(isHighCalorie: true)
// 2
} else if dynamicConstraints != lowCalorieConstraints {
  updateDynamicConstraints(isHighCalorie: false)
}

Avoiding unnecessary constraints activation and deactivation

Similar to the beverage’s high-calorie status, whether the beverage post belongs to a frequent user also has a role in TableViewCell user interface. You can activate and deactivate the badge image view’s constraints depending on isFrequentUser. However, this is extraneous work on the layout engine. Whenever possible, choose to activate the constraints once, and you can use isHidden to show or hide a view, which is less taxing on the system.

if beverage?.isFrequentUser ?? false {
  layoutConstraints += badgeImageViewConstraints
}
private var profileConstraints: [NSLayoutConstraint] {
  profileImageViewConstraints + badgeImageViewConstraints
}
NSLayoutConstraint.activate(layoutConstraints)

Unsatisfiable constraints

It’s good to know that unsatisfiable constraints can cause performance issues. Not only that, other problems may stem from unsatisfiable constraints. When there are unsatisfiable constraints, the layout engine will need to go through the process of figuring out which constraints to break in the hopes of giving you the desired layout.

Constraints dependencies

Now, you’ll look at how layout dependencies affect Auto Layout’s performance. Look at the following diagram:

Advanced Auto Layout features and cost

You may wonder how expensive it is to set layout constraint inequalities, constants and priorities. When given an inequality relation, the layout engine sees it as a single additional variable to solve. Inequalities are lightweight for the layout engine.

Apple optimizing UIKit

Apple is continuously optimizing UIKit ’s performance. Every year at WWWDC, Apple introduces a more performant way to integrate your data, behind the scene optimizations, new frameworks to make building dynamic and responsive layouts easy and so much more.

Key points

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.