FPS and jank
An average of 60 FPS does not mean the app is smooth. A capture that averages 58 FPS can still drop a frame every second, and users notice each one.
What the counter measures
Section titled “What the counter measures”iOS presents frames at a fixed interval: 16.7 ms on a 60 Hz screen and 8.3 ms on a 120 Hz ProMotion display. A frame is dropped when its work is not finished in time. The counter reports how many frames were actually presented each second.
On a 120 Hz device, a steady 60 FPS is not a problem. ProMotion runs at half rate when content is static. A real problem is 120 FPS falling to 40 while the user is dragging.
Read the drops, not the average
Section titled “Read the drops, not the average”In a KeyMob capture:
- Find the drops. Look for places where the line falls sharply and recovers.
- Note when they happen. At launch, on the first scroll, or each time an image loads?
- Check the other counters at the same moment. This identifies the cause.
| At the drop | Likely cause |
|---|---|
| CPU spikes | Main-thread work: layout, JSON parsing, image decoding or a synchronous file read |
| GPU spikes, CPU flat | Render-bound: overdraw, blur, shadows, offscreen rendering or too many layers |
| Memory jumps | A large allocation, often a full-resolution image decoded for a thumbnail |
| Network active | Waiting on a request on the wrong thread |
| No change | Blocking outside your process, or thermal throttling |
Common causes
Section titled “Common causes”- Image decoding on the main thread. Displaying a 4000-pixel photo in a 200-pixel cell decodes the full image. Downsample images before display.
- Views that are recreated instead of reused. A list that rebuilds views instead of recycling them uses more CPU the faster the user scrolls.
- Blur and shadows. Both are expensive on a mobile GPU. For shadows on moving views, set an explicit shadow path.
- Synchronous work in scroll callbacks. Any disk or network access during a drag causes visible stutter.
- Auto Layout in deep view hierarchies. Constraint solving cost grows faster than the number of views.
Testing tips
Section titled “Testing tips”- Use the oldest device you support. The 16.7 ms frame budget is fixed. A fast chip hides inefficient code that an older one exposes.
- Let the device cool down. Stutter caused by throttling cannot be fixed in code.
- Repeat the same interaction each time. Same list, same distance, same speed.
- Capture over USB. Wi-Fi sampling adds its own jitter, which looks the same as the stutter you are investigating.
Beyond frame rate
Section titled “Beyond frame rate”Some stutter does not show up in FPS, for example a tap that takes 300 ms to respond, or an animation that starts late. Check the CPU trace and the live log around the interaction. A long gap in log output during a drag is often the clearest sign that something blocked.
