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
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.
… into thumbnail key, which effect next time query from disk This is known issue in history which need a refactory. Currently have to workaround
📝 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
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
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.
SDIsThumbnailKeyrelies on a hardcoded substring"-Thumbnail("to identify thumbnail keys. If the key format generated bySDThumbnailedKeyForKeyever changes, this detection silently breaks. The// TODO, remove thismarkers 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.
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
shouldCacheToMemoryis now dead code.The variable
shouldCacheToMemoryis 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@notecomments.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.
SDIsThumbnailKeyrelies on finding the literal substring"-Thumbnail("in the key. While the format is currently consistent (generated bySDThumbnailedKeyForKeyviaSDTransformedKeyForKey), 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 withimage.sd_isThumbnailmitigates 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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters