Fix the issue that thumbnail decoding will store the fulll image data into thumbnail key, which effect next time query from disk by dreampiggy · Pull Request #3866 · SDWebImage/SDWebImage

@dreampiggy

@dreampiggy dreampiggy commented

Feb 6, 2026

edited by coderabbitai bot

Loading

New Pull Request Checklist

  • I have read and understood the CONTRIBUTING guide

  • I have read the Documentation

  • I have searched for a similar pull request in the project and found none

  • I have updated this branch with the latest master to avoid conflicts (via merge from master or rebase)

  • I have added the required tests to prove the fix/feature I am adding

  • I have updated the documentation (if necessary)

  • I have run the tests and they pass

  • I have run the lint and it passes (pod lib lint)

This merge request fixes / refers to the following issues: ...

Pull Request Description

This is known issue in history which need a refactory. Currently have to workaround.

See related PR in 64c5ff5

Summary by CodeRabbit

  • Bug Fixes
    • Thumbnails are no longer persisted as full cached image data, reducing disk storage and avoiding unintended thumbnail retention.
  • Refactor
    • Disk cache reads no longer implicitly trigger historical background memory-sync; disk-hit images are now made available in memory immediately.
  • Documentation
    • Updated API notes to clarify the new disk-to-memory caching behavior.

@dreampiggy

… into thumbnail key, which effect next time query from disk

This is known issue in history which need a refactory. Currently have to workaround

@coderabbitai

📝 Walkthrough

Walkthrough

SDImageCache changed encoding and thumbnail-storage behavior, removed synchronous disk→memory sync, and added a cache-options helper. SDWebImageManager now synchronously writes disk cache hits back into the memory cache.

Changes

Cohort / File(s) Summary
Cache core and encoding
SDWebImage/Core/SDImageCache.m
Imported UIImage+MultiFormat.h; prevented storing thumbnail data for thumbnail keys; adjusted store/encode logic to prefer image-provided sd_imageData for animated images and use coder fallback for non-animated; removed synchronous disk→memory sync; added +imageOptionsFromCacheOptions: helper.
Public API comments
SDWebImage/Core/SDImageCache.h
Documentation updates noting removal of historical behavior where disk cache hits were written back to memory (comments only).
Manager cache behavior
SDWebImage/Core/SDWebImageManager.m
On disk cache hits (cacheType == Disk) with a non-nil cachedImage, now synchronously stores that image into the memory cache (adds write-back to memory for disk results).
Tests
Tests/Tests/SDWebImageManagerTests.m
Adjusted test to remove assertion expecting thumbnail disk queries to write into memory (reflects new disk→memory semantics).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Manager as SDWebImageManager
    participant Cache as SDImageCache
    participant Disk
    participant Memory

    Client->>Manager: request image for key
    Manager->>Cache: query cache for key
    Cache->>Memory: check memory cache
    alt not in memory
        Cache->>Disk: read disk data
        Disk-->>Cache: disk image/data
        Cache-->>Manager: return cachedImage (cacheType: Disk)
    else in memory
        Cache-->>Manager: return cachedImage (cacheType: Memory)
    end
    alt returned from Disk
        Manager->>Memory: store cachedImage in memory cache (synchronous write-back)
    end
    Manager-->>Client: return cachedImage
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I nibbled through the cache and quay,
Kept tiny thumbs light on their way.
Disk handed back what memory missed,
I stitched it quick — a tiny twist.
Hooray for hops and faster display! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main bug fix: preventing thumbnail decoding from storing full image data under the thumbnail key. It clearly summarizes the core issue and its impact on disk cache queries, matching the primary changes in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@SDWebImage/Core/SDImageCache.m`:
- Around line 264-270: The current branch sets data = nil for thumbnails but
still falls through to the re-encoding path, which will convert animated
thumbnails (objects responding to animatedImageData) into a static/partial
representation; change the logic in SDImageCache.m so that when
image.sd_isThumbnail && SDIsThumbnailKey(key) and image
respondsToSelector:`@selector`(animatedImageData) you explicitly skip disk storage
for that image (e.g., set a flag like shouldStoreToDisk = NO or early-return
from the disk-write path) instead of allowing the re-encode; update uses of
data/shouldStoreToDisk in the later re-encoding and storeImage paths so animated
thumbnails remain in-memory-only to preserve frames and avoid lossy re-encoding.
🧹 Nitpick comments (1)
SDWebImage/Core/SDImageCache.m (1)

22-27: Fragile string-based key detection acknowledged as temporary.

SDIsThumbnailKey relies on a hardcoded substring "-Thumbnail(" to identify thumbnail keys. If the key format generated by SDThumbnailedKeyForKey ever changes, this detection silently breaks. The // TODO, remove this markers indicate awareness — just flagging to ensure the follow-up refactor (likely centralizing the key-format check in one place) stays on the radar.

Comment on lines +264 to 270

if (image.sd_isThumbnail && SDIsThumbnailKey(key)) {
// Currently we have no solid way to store thumbnail image's correct data
data = nil;
} else if (!data && [image respondsToSelector:@selector(animatedImageData)]) {
// If image is custom animated image class, prefer its original animated data
data = [((id<SDAnimatedImage>)image) animatedImageData];
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Correctness looks good; note subtle behavioral change for animated thumbnails.

Setting data = nil for thumbnails correctly prevents storing the full-size original data under a thumbnail key. The code then falls through to the re-encoding path (line 272), which will encode the actual thumbnail-sized image — this is the right fix.

However, the else if structure means animated thumbnails (sd_isThumbnail && SDIsThumbnailKey(key) and conforming to SDAnimatedImage) will skip the animatedImageData path entirely. Their original animated data (which is full-size) would reproduce the same bug, so skipping is correct — but re-encoding an animated thumbnail from the decoded image may lose frames or produce a static image. Worth confirming this edge case is acceptable or whether animated thumbnails should skip disk storage altogether (e.g., only cache in memory).

#!/bin/bash
# Check how sd_isThumbnail is set and if animated images can be thumbnails
echo "=== sd_isThumbnail property definition ==="
rg -n 'sd_isThumbnail' --type=objc -C3

echo ""
echo "=== SDThumbnailedKeyForKey definition ==="
rg -n 'SDThumbnailedKeyForKey' --type=objc -C3

echo ""
echo "=== Where thumbnail images are stored (calls to storeImage with thumbnail context) ==="
rg -n 'sd_isThumbnail\s*=' --type=objc -C3
🤖 Prompt for AI Agents
In `@SDWebImage/Core/SDImageCache.m` around lines 264 - 270, The current branch
sets data = nil for thumbnails but still falls through to the re-encoding path,
which will convert animated thumbnails (objects responding to animatedImageData)
into a static/partial representation; change the logic in SDImageCache.m so that
when image.sd_isThumbnail && SDIsThumbnailKey(key) and image
respondsToSelector:`@selector`(animatedImageData) you explicitly skip disk storage
for that image (e.g., set a flag like shouldStoreToDisk = NO or early-return
from the disk-write path) instead of allowing the re-encode; update uses of
data/shouldStoreToDisk in the later re-encoding and storeImage paths so animated
thumbnails remain in-memory-only to preserve frames and avoid lossy re-encoding.

@dreampiggy

@dreampiggy

coderabbitai[bot]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
SDWebImage/Core/SDImageCache.m (1)

655-659: 🛠️ Refactor suggestion | 🟠 Major

shouldCacheToMemory is now dead code.

The variable shouldCacheToMemory is computed (lines 655-659) but never referenced afterward. The disk-to-memory write-back logic that previously consumed it has been removed from this block. This should be cleaned up.

🧹 Remove unused variable
         } else if (diskData) {
             // the image memory cache miss, need image data and image
-            BOOL shouldCacheToMemory = YES;
-            if (context[SDWebImageContextStoreCacheType]) {
-                SDImageCacheType cacheType = [context[SDWebImageContextStoreCacheType] integerValue];
-                shouldCacheToMemory = (cacheType == SDImageCacheTypeAll || cacheType == SDImageCacheTypeMemory);
-            }
             // Special case: If user query image in list for the same URL, to avoid decode and write **same** image object into disk cache multiple times, we query and check memory cache here again. See: `#3523`
🤖 Fix all issues with AI agents
In `@SDWebImage/Core/SDImageCache.h`:
- Around line 340-341: Fix the typo in the `@return` doc for the method that
returns a SDImageCacheToken in SDImageCache.h: replace the garbled phrase "will
callback immediately when cancellederation, will callback immediately when
cancelled" with a clear sentence such as "a SDImageCacheToken instance
representing the cache operation; its completion handler will be called
immediately if the operation is cancelled." Keep the rest of the warning line
unchanged; update the comment above the method that returns SDImageCacheToken to
ensure correct grammar and clarity.
🧹 Nitpick comments (2)
SDWebImage/Core/SDImageCache.h (1)

315-315: Vague version reference in @note comments.

The added notes say "From new version" without specifying which version. Consider using the actual version number (e.g., "From v5.x.y") so users of the public API can reason about behavioral differences across releases.

Also applies to: 328-328, 342-342, 357-357

SDWebImage/Core/SDImageCache.m (1)

22-27: Fragile thumbnail key detection via string matching.

SDIsThumbnailKey relies on finding the literal substring "-Thumbnail(" in the key. While the format is currently consistent (generated by SDThumbnailedKeyForKey via SDTransformedKeyForKey), this string-matching approach creates a maintenance risk—if the key format ever changes or evolves, the detection will silently break. Additionally, a URL could theoretically contain that substring and cause false positives, though the dual condition with image.sd_isThumbnail mitigates this in practice.

The TODO comment confirms this is a known concern. Consider extracting the thumbnail key format into a shared constant and deriving detection logic from the same place that constructs the keys, ensuring detection stays in sync with generation.

Comment on lines 340 to 341

* @return a SDImageCacheToken instance containing the cache operation, will callback immediately when cancellederation, will callback immediately when cancelled
* @warning If you query with thumbnail cache key, you'd better not pass the thumbnail pixel size context, which is undefined behavior.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Pre-existing typo in doc comment.

Line 340 reads: "will callback immediately when cancellederation, will callback immediately when cancelled" — looks like a copy-paste artifact. Not introduced by this PR but worth fixing while you're editing these doc blocks.

📝 Suggested fix
- * `@return` a SDImageCacheToken instance containing the cache operation, will callback immediately when cancellederation, will callback immediately when cancelled
+ * `@return` a SDImageCacheToken instance containing the cache operation, will callback immediately when cancelled
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

* @return a SDImageCacheToken instance containing the cache operation, will callback immediately when cancellederation, will callback immediately when cancelled
* @warning If you query with thumbnail cache key, you'd better not pass the thumbnail pixel size context, which is undefined behavior.
* `@return` a SDImageCacheToken instance containing the cache operation, will callback immediately when cancelled
* `@warning` If you query with thumbnail cache key, you'd better not pass the thumbnail pixel size context, which is undefined behavior.
🤖 Prompt for AI Agents
In `@SDWebImage/Core/SDImageCache.h` around lines 340 - 341, Fix the typo in the
`@return` doc for the method that returns a SDImageCacheToken in SDImageCache.h:
replace the garbled phrase "will callback immediately when cancellederation,
will callback immediately when cancelled" with a clear sentence such as "a
SDImageCacheToken instance representing the cache operation; its completion
handler will be called immediately if the operation is cancelled." Keep the rest
of the warning line unchanged; update the comment above the method that returns
SDImageCacheToken to ensure correct grammar and clarity.

@dreampiggy