-
Profile, fix, and verify: Improve app responsiveness with Instruments
Tackle app responsiveness issues with a clear workflow. Explore the Swift Concurrency instrument, Time Profiler, and System Trace to pinpoint bottlenecks. Discover how to use top functions and run comparisons to measure your improvements and confirm your fixes. And learn about other enhancements in Instruments which make each iteration of this cycle faster than ever, so you can deliver a smoother user experience in less time.
Chapters
- 0:00 - Introduction
- 1:12 - Diagnostic flow
- 7:06 - Sampling data visualization
- 16:01 - Execution contention
- 20:29 - System blocking
- 26:07 - Next steps
Resources
Related Videos
WWDC26
WWDC25
WWDC23
WWDC22
-
Search this video…
-
-
5:41 - Add signpost interval around Lasso Selection
// Add signpost interval around Lasso Selection import os.signpost let signposter = OSSignposter(subsystem: “Demo App", category: .pointsOfInterest) var lassoIntervalState: OSSignpostIntervalState? = nil func lassoSelectionUpdated() { lassoIntervalState = signposter.beginInterval("Lasso Selection") // Update selection in canvas… } func lassoSelectionEnded() { // Finalize lasso selection... signposter.endInterval("Lasso Selection", lassoIntervalState!) } -
12:11 - Existentials
// Existentials protocol Foo { } struct TypeA: Foo { } struct TypeB: Foo { } func bar(_ foo: any Foo) { } -
12:39 - Concrete Types
// Concrete types protocol Foo { } struct TypeA: Foo { } struct TypeB: Foo { } func bar(_ a: TypeA) { } func bar(_ b: TypeB) { } -
12:46 - Concrete Types + Generics
// Concrete types protocol Foo { } struct TypeA: Foo { } struct TypeB: Foo { } func bar(_ a: TypeA) { } func bar(_ b: TypeB) { } // Generics protocol Foo { } struct TypeA: Foo { } struct TypeB: Foo { } func bar<T: Foo>(_ generic: T) { } -
12:49 - Concrete Types + Generics + Enums
// Concrete types protocol Foo { } struct TypeA: Foo { } struct TypeB: Foo { } func bar(_ a: TypeA) { } func bar(_ b: TypeB) { } // Generics protocol Foo { } struct TypeA: Foo { } struct TypeB: Foo { } func bar<T: Foo>(_ generic: T) { } // Enums enum Foo { case a(TypeA) case b(TypeB) } struct TypeA { } struct TypeB { } func bar(_ enum: Foo) { } -
18:24 - Thumbnail Rendering
// Thumbnail rendering let drawingData = note.drawingData let canvasImages = note.decodeCanvas() thumbnail = await Task(name: "Render Thumbnail") { await renderThumbnail(drawingData: drawingData, canvasImages: canvasImages, size: CGSize(width: 300, height: 240)) }.value -
18:29 - Thumbnail Rendering Off Main Actor
// Thumbnail rendering off Main Actor let drawingData = note.drawingData let canvasImages = note.decodeCanvas() thumbnail = await Task(name: "Render Thumbnail") { @concurrent in await renderThumbnail(drawingData: drawingData, canvasImages: canvasImages, size: CGSize(width: 300, height: 240)) }.value -
24:12 - File Saving
// File saving let encoder = PropertyListEncoder() encoder.outputFormat = .binary guard let data = try? encoder.encode(snapshots) else { return } let id = signposter.beginInterval("Writing To File") try? data.write(to: fileURL, options: .atomic) signposter.endInterval("Writing To File", id) -
24:25 - File Saving off Main thread
// File saving Task { @concurrent in let encoder = PropertyListEncoder() encoder.outputFormat = .binary guard let data = try? encoder.encode(snapshots) else { return } let id = signposter.beginInterval("Writing To File") try? data.write(to: fileURL, options: .atomic) signposter.endInterval("Writing To File", id) }
-
-
- 0:00 - Introduction
Overview of how Instruments 27 helps developers understand and optimize app responsiveness across the software stack abstraction layers.
- 1:12 - Diagnostic flow
Learn the four-step mental model — CPU saturation, sampling data visualization, execution contention, and system blocking — for systematically triaging hangs and frame drops.
- 7:06 - Sampling data visualization
Explore how Instruments' Call Tree, Flame Graph, and the new Top Functions mode transform raw CPU samples into actionable views for identifying performance bottlenecks.
- 16:01 - Execution contention
Discover how the Swift Executors instrument reveals when render-thumbnail tasks saturate the Main Actor, and how adding the @concurrent attribute moves work off the main thread to resolve UI hangs.
- 20:29 - System blocking
Use System Trace and the new Inspector panel to diagnose low-CPU hangs caused by synchronous file I/O blocking the main thread, and learn to fix them by moving the work to a background Swift task.
- 26:07 - Next steps
Key takeaways on matching the right Instruments template to each class of performance problem, plus links to related sessions on CPU optimization, Swift Concurrency, and hang analysis.