2023 SwiftUI & UI Frameworks
WWDC23 · 22 min · SwiftUI & UI Frameworks
Demystify SwiftUI performance
Learn how you can build a mental model for performance in SwiftUI and write faster, more efficient code. We’ll share some of the common causes behind performance issues and help you triage hangs and hitches in SwiftUI to create more responsive views in your app.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 16 snippets
DogView
struct DogView: View {
(\.isPlayTime) private var isPlayTime
var dog: Dog
var body: some View {
Text(dog.name)
.font(nameFont)
Text(dog.breed)
.font(breedFont)
.foregroundStyle(.secondary)
ScalableDogImage(dog)
DogDetailView(dog)
LetsPlayButton()
.disabled(dog.isTired)
}
}
} ScalableDogImage
struct ScalableDogImage: View {
private var scaleToFill = false
var dog: Dog
var body: some View {
dog.image
.resizable()
.aspectRatio(
contentMode: scaleToFill ? .fill : .fit)
.frame(maxHeight: scaleToFill ? 500 : nil)
.padding(.vertical, 16)
.onTapGesture {
withAnimation { scaleToFill.toggle() }
}
}
} printChanges
expression Self._printChanges() ScalableDogImage + printChanges
struct ScalableDogImage: View {
private var scaleToFill = false
var dog: Dog
var body: some View {
let _ = Self._printChanges()
dog.image
.resizable()
.aspectRatio(
contentMode: scaleToFill ? .fill : .fit)
.frame(maxHeight: scaleToFill ? 500 : nil)
.padding(.vertical, 16)
.onTapGesture {
withAnimation { scaleToFill.toggle() }
}
}
} ScaleableDogImage
struct ScalableDogImage: View {
private var scaleToFill = false
var dog: Dog
var body: some View {
dog.image
.resizable()
.aspectRatio(
contentMode: scaleToFill ? .fill : .fit)
.frame(maxHeight: scaleToFill ? 500 : nil)
.padding(.vertical, 16)
.onTapGesture {
withAnimation { scaleToFill.toggle() }
}
}
} Updated DogView
struct DogView: View {
(\.isPlayTime) private var isPlayTime
var dog: Dog
var body: some View {
Text(dog.name)
.font(nameFont)
Text(dog.breed)
.font(breedFont)
.foregroundStyle(.secondary)
ScalableDogImage(dog)
DogDetailView(dog)
LetsPlayButton()
.disabled(dog.isTired)
}
}
} Final DogView
struct DogView: View {
(\.isPlayTime) private var isPlayTime
var dog: Dog
var body: some View {
DogHeader(name: dog.name, breed: dog.breed)
ScalableDogImage(dog.image)
DogDetailView(dog)
LetsPlayButton()
.disabled(dog.isTired)
}
}
} DogRootView and FetchModel
struct DogRootView: View {
private var model = FetchModel()
var body: some View {
DogList(model.dogs)
}
}
class FetchModel {
var dogs: [Dog]
init() {
fetchDogs()
}
func fetchDogs() {
// Takes a long time
}
} Updated DogRootView and FetchModel
struct DogRootView: View {
private var model = FetchModel()
var body: some View {
DogList(model.dogs)
.task { await model.fetchDogs() }
}
}
class FetchModel {
var dogs: [Dog]
init() {}
func fetchDogs() async {
// Takes a long time
}
} List
List {
ForEach(dogs) {
DogCell(dog: $0)
}
} List Again
List {
ForEach(dogs) {
DogCell(dog: $0)
}
} List Fixed
List {
ForEach(tennisBallDogs) { dog in
DogCell(dog)
}
} Sectioned List
// Sectioned example
struct DogsByToy: View {
var model: DogModel
var body: some View {
List {
ForEach(model.dogToys) { toy in
Section(toy.name) {
ForEach(model.dogs(toy: toy)) { dog in
DogCell(dog)
}
}
}
}
}
} DogTable
struct DogTable: View {
var dogs: [Dog]
var body: some View {
Table(of: Dog.self) {
// Columns
} rows: {
ForEach(dogs) { dog in
TableRow(dog)
}
}
}
} DogTable Brief
struct DogTable: View {
var dogs: [Dog]
var body: some View {
Table(of: Dog.self) {
// Columns
} rows: {
ForEach(dogs)
}
}
} DogTable Different IDs
struct DogTable: View {
var dogs: [Dog]
var body: some View {
Table(of: Dog.self) {
// Columns
} rows: {
ForEach(dogs) { dog in
TableRow(dog.bestFriend)
}
}
}
} Related sessions
-
13 min -
30 min -
43 min -
40 min