Skip to content

Keep calling the Nuke 13 willCache - #1057

Closed
kean wants to merge 1 commit into
mainfrom
fix/will-cache-nuke-13-compat
Closed

kean wants to merge 1 commit into
mainfrom
fix/will-cache-nuke-13-compat

Conversation

@kean

@kean kean commented Oct 31, 2026

Copy link
Copy Markdown
Owner

A Nuke 13 willCache(data:image:for:pipeline:completion:) compiles against Nuke 14 with no diagnostic and was never called, so a delegate that kept private images off the disk silently started writing them. The method is a requirement again and the default async willCache forwards to it. It's soft-deprecated in the docs only: @available(*, deprecated) warns inside the default implementation and says nothing to the delegate. The guide and nuke-migrate now say it keeps working, and keep the warning for the other old delegate methods.

The pipeline waits for a closure that Nuke 13 didn't wait for, so a closure that is never called resolves to nil when it's released, and only the first call counts. With a plain continuation, as first proposed, the first case hung the load and the second crashed it.

Proof

ImagePipelineDelegateCachingTests, macOS, Xcode 27.1 RC. The suite went from 12 to 21 tests:

Delegate main This PR
Nuke 13, completion(nil) callCount → 0, ["…/example.jpeg": 22789 bytes] stored 1 call, nothing stored
Same, declared in an extension not called, 22789 bytes stored called, nothing stored
Same, encoded image (processor, .automatic) callCount → 0, 7 bytes stored 1 call, nothing stored
Nuke 13, replaces the data not called, original stored replacement stored
Nuke 13, completes on another thread not called, original stored replacement stored
Nuke 13, never calls completion not called, 22789 bytes stored image delivered, nothing stored
Nuke 13, calls completion twice not called, stored first call wins
No willCache at all stored stored
Both forms async form wins async form wins

A Swift 5 mode client in Release, with Nuke built at deployment target macOS 15, where the actor isolation checks fire. Same delegates, each run with a real pipeline:

completion Plain continuation This PR
Called synchronously, on a global queue, on main image, 0 stored image, 0 stored
Never called hang, leaked its continuation image, 0 stored
Called twice SIGTRAP, tried to resume its continuation more than once image, 0 stored

Cost of pipeline.willCache per store, Release, 10 interleaved A/B rounds, medians:

main This PR
No delegate 14.6 ns 14.3 ns
Delegate with the async form 30.4 ns 29.8 ns
Delegate with no willCache 32.5 ns 98.7 ns
Full load through a stub loader, same delegate 7.81 µs 7.74 µs
Full load through a stub loader, no delegate 10.05 µs 10.53 µs

isDefaultDelegate still returns before the delegate is touched, so the no-delegate row runs no new code. The last row is noise: the ranges overlap (7.7–13.6 and 8.0–13.5 µs) at a load average of 40. The real cost is +66 ns per disk write, and only for a delegate that doesn't implement willCache.

No new compiler warnings: a clean build of Nuke and its tests gives the same warnings as main, including the conformances above. The full Nuke scheme passes on macOS (1,739 tests, 1 skipped), and so do make snippets, make lint, generate-llms.py --check, and a docbuild.

Not verified: Xcode 26 locally, because the 26.6 install here is damaged, so CI is the first compile on it. iOS and tvOS weren't run: the change has no platform code.

@kean
kean force-pushed the fix/will-cache-nuke-13-compat branch from bfe2cef to 20ec614 Compare October 31, 2026 20:27
A Nuke 13 willCache(data:image:for:pipeline:completion:) compiled against
Nuke 14 with no diagnostic and was never called, so a delegate that kept
private images off the disk silently stopped doing so. The method is a
requirement again, and the default implementation of the async one calls it.

The pipeline now waits for a closure that Nuke 13 didn't wait for, so one that
is never called resolves to nil when it's released, and only the first call
counts.
@kean
kean force-pushed the fix/will-cache-nuke-13-compat branch from 20ec614 to 425799d Compare November 3, 2026 00:51
@kean kean added this to the 14.0 milestone Nov 8, 2026
@kean kean closed this Nov 8, 2026
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