Async image loading from url inside a UITableView cell - image changes to wrong image while scrolling
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Wrong images appearing in reused table view cells is a classic UIKit issue. The root cause is asynchronous network completion arriving after the cell has been reused for a different row. The fix combines request cancellation, identity checks, and optional caching.
Why Cell Reuse Causes Image Mismatch
UITableView reuses cell instances as you scroll. If an image request started for old row data completes later, it can set an image on a cell now representing a different item. Without guardrails, fast scrolling makes this bug frequent.
A robust design gives each cell a model identifier and cancels outdated tasks in prepareForReuse.
The currentID check ensures stale callbacks are ignored.
Centralized Image Loader with Cache
A loader service prevents duplicated requests and improves scroll performance through caching.
Inject one loader instance into your table view controller so all cells share cache state.
Data Source Integration Pattern
Always bind cells from immutable view-model data keyed by stable IDs. Avoid using index path as identity because rows can move after inserts or deletes.
In cellForRowAt, pass row.id and row.avatarURL into configure. This keeps asynchronous completion aligned with logical row identity.
Debugging and Verification
To verify the fix, simulate slow network conditions and perform rapid scroll tests. Log both requested ID and applied ID inside completion handlers. If logs ever differ, stale write protection is missing.
You can also profile cache hit rates and request counts. After optimization, repeated scroll passes should show fewer network fetches and fewer visible image flashes.
Prefetching and Cancellation at Scale
For long lists, adopt UITableViewDataSourcePrefetching so image requests start before cells appear. Pair prefetch with request deduplication in your loader to avoid multiple downloads of the same URL. If a prefetched row scrolls away, cancel low-priority requests unless another visible cell still needs them.
This architecture improves perceived smoothness and reduces visible image pop-in. It also prepares your code for offline cache layers if product requirements later include low-connectivity support.
Common Pitfalls
- Setting images in completion blocks without checking cell identity.
- Forgetting to cancel previous network tasks in
prepareForReuse. - Using index paths as long-lived identity keys.
- Creating one loader per cell and defeating cache reuse.
- Updating UI from background threads after image decode.
Summary
- Cell reuse plus async network calls causes wrong-image bugs.
- Cancel old tasks and track a stable model identifier per cell.
- Ignore stale callbacks by comparing identifier at completion time.
- Centralize loading and caching for consistency and speed.
- Test under slow-network and fast-scroll scenarios before release.

