WWDC26: Power and Performance Group Lab - Q&A
Direct answers from Apple Engineers during WWDC26
Power and performance work is easy to postpone until the app feels slow, drains battery, or starts showing bad field metrics. But the best answers from this lab all point in the same direction: measure first, understand the real bottleneck, and optimize the parts that users actually experience.
As usual, the goal is simple: make the questions easier to scan, easier to revisit, and easier to connect with real app development problems.
I tried to preserve the original wording and combine related answers where appropriate. However, some inaccuracies or mismatches are still possible.
Enjoy! And subscribe so you don’t miss the next Lab.
As a beginner in iOS development, what are the main factors that affect app power usage and performance in SwiftUI, and how can I design simple apps that avoid battery drain and lag?
For SwiftUI, start by separating views from their inputs. Make sure views are only watching the state they actually depend on. If a variable changes but a view does not visually depend on it, that change should not cause unnecessary redraws.
@Observable helps here because SwiftUI tracks only the fields a view reads. That gives you a cleaner dependency model and helps avoid updates for data the view does not care about.
Use Instruments to confirm what is really happening. The SwiftUI instrument can show view updates and dependency relationships, including cause-and-effect graphs. If the issue is power-related, use Power Profiler as well. SwiftUI performance work often improves power too, because reducing unnecessary computation also reduces energy use.
But do not assume SwiftUI is the problem. If you are new to performance work, start with the overall picture. Your battery drain might come from an algorithm, file I/O, networking, location, or background work. Measure first, then decide where to optimize.
What’s the biggest power mistake you see in many apps that developers don’t realize they’re making?
One of the biggest mistakes is not having enough telemetry or instrumentation. Without measurement, developers often optimize the wrong thing. A single customer report can point to one issue, while field analytics may reveal a broader and more important power problem.
Another common issue is not accounting for different app states and data sizes. A database write might look fine during local testing but become expensive for users with much larger datasets. That can show up in Xcode Organizer energy logs even if you never reproduce it at your desk.
You also need to remember that everything uses power: file system access, network requests, location updates, CPU work, GPU work, and display usage. If you can do less work, batch work better, or make network requests half as often, that can be a direct power win.
Use real-world profiling where possible. Power Profiler supports untethered workflows, where you record traces on-device for longer periods and analyze them later. That helps capture behavior that may not appear in a controlled desk setup.
What is the best documentation for Instruments? Are there any written guides?
The recommended starting point is the Instruments tutorials. They were written by an Instruments engineer and are designed to feel like someone is walking you through the app step by step.
The tutorials include an associated project with built-in performance issues, so you can learn the full loop: profile the app, identify hangs or slow paths, understand how they appear visually, fix them, and then verify the improvement.
For beginners, Time Profiler with the flame graph view is also a good first tool. Flame graphs make it easier to see where time is going because the expensive call stacks are visually obvious. Top Functions is another useful view because it flattens the call tree and shows expensive helper, compiler, and runtime functions more directly.
If documentation is missing for a specific workflow or instrument, the panel encouraged developers to file feedback.
Our app shows UIKit and SwiftUI screens without much background work, but it is still using high battery according to Xcode. What are the best practices to know what is going on and why this might be happening?
First, distinguish foreground energy from background energy. UIKit and SwiftUI work should usually show up as foreground energy. If you are seeing background energy drain, look for background tasks, location work, networking, or other work scheduled while the app is not in the foreground.
Power Profiler is a good starting point, especially in untethered mode. Record a trace on the device while using the app in realistic conditions, then bring the trace back to the Mac and inspect it in Instruments.
Power Profiler can break down energy use by subsystem, such as CPU, GPU, display, networking, and other sources. That helps narrow the issue. For example, high display energy may come from brightness or frequent visual changes, while high network energy may point to background requests.
Do not rely only on what you can reproduce while tethered to Xcode. Some power problems only appear when the app is used in real-world conditions.
A theme object like colors and tokens is injected through EnvironmentObjectand read in every atomic component, dozens of nesting levels, hundreds of components on screen. At what scale does this become a bottleneck, and is there a recommended alternative?
There is no single numeric threshold. The cost depends on what the views are doing, how often the environment value changes, and how much downstream work those changes cause.
Putting values in the environment can be a useful abstraction for passing data down a view tree. The important question is whether changing that environment value causes a large amount of unnecessary invalidation.
Use the SwiftUI instrument to see the downstream effect of those changes. It can help you understand whether the environment object is actually causing expensive updates or whether it is fine in your specific case.
If the object changes frequently and many views read it, you may need to split the data, move rapidly changing values closer to the leaf views that need them, or reduce the amount of state that is globally injected.
How would you load large data sets like 50,000 or 500,000 records in SwiftUI tables, and how would you analyze performance and regressions using MetricKit?
Start by asking how much data the user experience actually needs to load at once. If the UI is not displaying all 500,000 records, loading everything immediately is probably unnecessary work.
Load only what you need. Use batching, pagination, lazy containers, and model-side filtering so SwiftUI receives the data it actually needs to display. SwiftUI has lazy stacks and lists that can help load views as they come on screen.
For MetricKit, use state reporting to understand what the app was doing when a metric changed. Rather than logging a rapidly changing number like the exact item count on every update, group states into meaningful categories such as small, medium, and large batch sizes. That gives you useful slices of performance data without creating excessive logging overhead.
This lets you compare how different loading strategies behave in the field, and it helps you decide where to invest optimization effort.
How does iOS 27 prioritize background tasks when the system is under heavy Apple Intelligence workloads?
It depends on which system resources are being used. Many Apple Intelligence workloads run on the Neural Engine or in Private Cloud Compute. If your app is using CPU while the intelligence workload is using a different resource, they may be able to run at the same time without much conflict.
Still, background tasks should be designed in small chunks. If the system needs to pause or delay work, your task should be able to resume without starting over from the beginning. That makes progress more reliable even when the system is busy.
Instruments also adds more visibility here. System Trace can show thread priorities and help you understand whether you are assigning QoS incorrectly, or whether another task preempted your thread.
The general principle is that the system tries to schedule work automatically to preserve the best user experience. Your job is to make background work resumable, appropriately prioritized, and not overly monolithic.
To avoid blocking the main thread, I perform expensive tasks on background threads. During launch this causes a lot of thread hops. How expensive is frequent thread hopping compared to thread blocking, and is there a better solution for performance?
Thread hopping has overhead, but if you are not doing it excessively, that overhead is usually small. It becomes a concern when it happens extremely frequently.
The bigger issue during launch is often doing too much work too early, or starting background work and then making the main thread wait for it before the first frame. That still blocks the user experience even if the work happens on background threads.
Focus on the minimum data needed to draw the first useful frame. Defer non-critical work until after launch. Cache previous results when possible. For example, if you fetch A/B test configuration during launch, consider using the cached result first and updating later.
Use Instruments to measure the problem. System Trace can show context switch counts and blocked thread states. Xcode Organizer can also show real-world launch metrics and call stacks for slow launches in shipped apps.
How should developers measure app launch time? Should they inspect low-level APIs to see when the process was created?
Use Apple’s tools instead of trying to infer launch time yourself from low-level APIs. MetricKit and Xcode Organizer measure launch efficiently and include parts of launch that your app process cannot measure on its own.
For example, they can account for the interval from when the user taps the app icon to when the first rendered screen appears. Your app code cannot directly measure the moment before your process exists.
This is the same kind of launch measurement Apple uses for its own apps. It avoids adding extra measurement overhead and gives you a user-focused view of launch performance.
Besides background tasks, what is the most common silent battery killer in SwiftUI? How much power does view over-invalidation actually drain, and what is the best Instruments workflow to catch it before release?
View over-invalidation can be a serious silent battery issue because it may not produce visible changes. The screen can look exactly the same while the CPU keeps recreating views in the background.
The key is to minimize unnecessary redraws. Keep dependencies precise, flatten overly deep hierarchies where appropriate, and avoid repeatedly dispatching background work just to fetch data for UI that could have been cached or computed once.
Use the SwiftUI instrument to find unnecessary view updates. Pair that with Power Profiler to understand the energy cost. If the extra invalidation is CPU-heavy, it can show up as foreground energy drain.
The larger principle still applies: cache when possible, avoid repetitive work, and measure before optimizing.
Are there performance improvements for very large lists and table views in SwiftUI for macOS 27? What are best practices for making long SwiftUI lists and tables work well with tens or hundreds of thousands of items?
For very large lists, keep the list structure as stable as possible. If cells constantly change size, that can force SwiftUI to recalculate what appears at each scroll offset. Stable row sizes are easier for SwiftUI to cache and reason about.
Use lazy data structures and lazy SwiftUI containers where appropriate. Also move filtering and data preparation into the model layer rather than putting conditionals and transformations directly inside ForEach. Give SwiftUI the final data it needs to display, not a giant unfiltered set it has to chew through during rendering.
Batch work and load only the visible or near-visible data. The same idea used for launch performance applies here: what is the minimum information needed for the next useful UI update?
I use AnyView for type erasure in several places. How expensive is it in practice? Is there a concrete threshold beyond which AnyView becomes a problem, or is avoiding it premature optimization?
AnyView and type erasure do add some overhead when creating views, so it is reasonable to avoid them when they are easy to avoid.
But do not contort your design just to remove AnyView everywhere. If it becomes measurable, then address it. Otherwise, you may spend time optimizing something that does not matter for your app.
This is a general performance principle: measure first. Some APIs have costs, but they exist for a reason. If using a type-erased view makes a design cleaner and does not show up in profiling, the time may be better spent elsewhere.
MetricKit state reporting and crash report extensions are new and noteworthy this year. Are there any other headlining developer tools worth looking at?
Xcode Organizer received important improvements, especially around Metric Goals. Metric Goals help you understand how your app compares to similar apps, which is useful because raw numbers are often hard to judge in isolation.
For example, a video app may naturally use more power than a simple utility app. Metric Goals give you a more meaningful baseline by comparing against apps in similar categories.
State reporting is also worth adopting. Combined with MetricKit, it lets you slice metrics by app state and identify where power, launches, hitches, or hangs are poor. That gives you a much clearer target for optimization.
If there is one thing developers should try from the new tools this year, what should it be?
Metric Goals are a strong starting point because they show how your metrics compare with similar apps. That helps you understand whether power, launch time, hitches, or hangs are genuinely worse than expected.
State reporting is the second big one. It lets you connect metrics to specific app states, so you can see where performance or power is getting worse. Together, Metric Goals and state reporting help move performance work from vague concern to targeted investigation.
Swift performance is something I’m genuinely passionate about and want to go deep on beyond WWDC sessions and Swift Evolution proposals. What does the pathway look like for building real deep expertise?
Experience is the main path. Build things, profile them, and inspect what actually happens. Instruments gives you many perspectives, including Time Profiler, SwiftUI instrument, and other templates that reveal what frameworks are doing behind the scenes.
For deeper Swift performance expertise, study how the standard library and open-source Swift packages are implemented. Look at benchmarks, inspect generated behavior, and experiment with changes. Combine that with Instruments so your mental model is grounded in measurements, not assumptions.
The important habit is to form hypotheses and then test them. Swift performance work is not only about knowing APIs. It is about understanding where time and energy are actually spent, then using the right tool or code change to improve the real bottleneck.
If I have a newer device but want to make sure performance is good on older devices, what should I do?
A simple first step is to turn on Low Power Mode. It reduces CPU performance to save battery, which can reveal issues that you may not see on a newer device running at full performance.
Use physical devices for profiling when possible. Simulator performance depends on the Mac, not the simulated device model, so it is not a reliable way to judge device performance.
Condition inducers can also help. They let you artificially induce system conditions such as thermal pressure without physically heating the device. Field data from MetricKit and Xcode Organizer is also valuable because it shows performance across real users, real devices, and real conditions.
Does using a lot of @Environment properties in a large SwiftUI app have any performance impact?
Reading values from the environment is not necessarily expensive by itself. The main performance issue is environment churn.
If values are placed in the environment and read by many views, that can be fine when they do not change frequently. Problems start when those environment values update often. Then every view that reads from the environment has to reevaluate whether something changed.
So the issue is not simply “many environment values.” The issue is frequently changing environment values across a deep view hierarchy. Use the SwiftUI instrument to verify whether that churn is actually causing rendering or update performance issues.
🏆Acknowledgments
A huge thank-you to everyone who joined and shared practical, performance-focused questions throughout the session. Your questions made the discussion useful for developers working on launch time, SwiftUI rendering, background work, MetricKit, Xcode Organizer, Instruments, power usage, and real-world field diagnostics.
The uploaded transcript does not include stable attendee nicknames for most questions, so the acknowledgments avoid inventing names. Question acknowledgments: the online WWDC audience who submitted and upvoted the Power and Performance questions.
Finally, a heartfelt thank-you to Cole, Terry, Yanni, Kasper, Kunal, and Marco for leading the session, sharing practical guidance, and explaining how to approach power and performance with measurement-first thinking.

