Asynchronous image downloader/cache for Monotouch
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In MonoTouch style iOS apps, image loading needs three things to feel correct: it must not block the UI thread, it should avoid downloading the same image repeatedly, and it must cope with view reuse so the wrong image does not flash into a recycled cell. An asynchronous image downloader with caching solves all three problems when it is built around memory cache, in-flight request reuse, and main-thread UI updates.
The Basic Design
A practical image loader usually has these pieces:
- an
HttpClientfor download - an in-memory cache for already decoded images
- optional disk cache for persistence
- a way to deduplicate concurrent requests for the same URL
Here is a compact C# example that works as the core of a MonoTouch or Xamarin.iOS image service:
The important detail is _inFlight. If several cells ask for the same URL at once, they share one download task instead of starting several identical network calls.
Update the UI on the Main Thread
iOS UI objects must be updated on the main thread. A table view cell might use the cache like this:
This keeps network and decoding work off the UI thread while ensuring the final assignment is safe.
Handle Cell Reuse Correctly
Table and collection views reuse cells. That means a cell might start loading image A, get reused, and then incorrectly display image A inside row B once the download finishes.
A simple defense is to store the expected URL on the cell:
Then verify it before assigning:
That small check prevents a lot of visual bugs.
Add Disk Cache When Needed
Memory cache is fast, but it disappears when the app is terminated or memory pressure clears it. For heavier image usage, save downloaded bytes to disk and check disk before going to the network.
The pattern is:
- look in memory
- look on disk
- download if missing
- store in both caches
Disk caching helps especially for large lists, avatars, and images revisited across screens.
Why Not Just Download Directly in the Cell
It is tempting to put HttpClient calls directly into view code, but that usually causes:
- duplicate downloads
- no shared cache
- harder cancellation and reuse handling
- UI code mixed with networking concerns
A dedicated image service gives you one place to handle caching, logging, reuse, and fallback behavior.
Common Pitfalls
The biggest pitfall is setting the image directly after await without checking whether the cell was reused for a different URL.
Another common issue is updating UIKit controls from a background thread. Network code can run off the main thread, but UI assignment should come back to the main thread.
People also often cache raw bytes but forget that decoding the image repeatedly still costs time. Caching decoded UIImage instances in memory helps a lot for scrolling performance.
Finally, do not ignore duplicate requests. Without in-flight request deduplication, a fast scroll through a table can trigger many identical downloads for the same image.
Summary
- Load images asynchronously so the UI thread stays responsive.
- Use memory caching to avoid repeated downloads and decoding.
- Deduplicate concurrent requests for the same URL.
- Guard against cell reuse before assigning the final image.
- Add disk cache when images are reused across screens or app launches.

