Skip to content

Add fallback sources and Low Data Mode to ImageRequest - #1102

Open
kean wants to merge 2 commits into
mainfrom
feat/fallback-sources
Open

kean wants to merge 2 commits into
mainfrom
feat/fallback-sources

Conversation

@kean

@kean kean commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

ImageRequest/alternatives loads another source when the request's own fails, and ImageRequest/lowDataURL loads a smaller image when Low Data Mode keeps it off the network. Each fallback is a load of its own, under its own cache keys, so a one-off 500 can't pin it in place of the real image, and every load tries the source again.

Proof

  • 63 new tests, most with MockDataLoader: request count and order, a later load trying the source again, the fallback's bytes under the fallback's key, coalescing, cancellation, ImagePrefetcher, LazyImage, metrics. With the fallback path disabled, 33 fail.
  • noDeduplicationGivenRequestKeptOffConstrainedNetworks fails on main (1 download for 2 tasks) and passes here. It covers the new allowsConstrainedNetworkAccess key field.
  • Nuke and NukeUI on macOS (1,822 and 637), iOS 27 and tvOS (1,866 and 647). The only stable failures, policyIsReevaluatedWhenMoreDataArrives and previewPolicyIsReevaluatedOnlyWhenTheDataDoubles, fail the same way on main on this Mac. Timing tests that failed in full runs at load average 150+ passed when rerun alone.
  • A request with no fallbacks: Container stays 112 bytes. Instructions retired, 7 interleaved rounds: create +0.3%, copy +0.2–0.3%, url +34, urlRequest +86. Memory hit and full load are inside their noise (5–10%).
  • Not exercised on a network that's actually in Low Data Mode: the failure comes from a mock and from a URLProtocol stub through a real URLSession.

kean added 2 commits November 2, 2026 19:24
A request can now list `alternatives` to load when its source fails, and a
`lowDataURL` to load when Low Data Mode keeps it off the network.

The fallbacks are per image task, above the task graph, and each source is a
load of its own. Tasks for one image share the load of its source whatever
they fall back to, so nothing changes in the keys, and a fallback is cached
under its own keys: a passing failure can't pin a mirror's image in the place
of the real one, and every load tries the source again.

A request kept off constrained networks no longer shares a fetch with one
that isn't, which also fixes that for a `URLRequest` that sets the flag.
@kean
kean force-pushed the feat/fallback-sources branch from 881bc72 to 11281e9 Compare November 3, 2026 00:51

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant