Use the memory bytes size, instead of pixel size to calculate the memory cost function

This commit is contained in:
DreamPiggy 2019-01-03 15:11:24 +08:00
parent b866c6aa97
commit 6dd92d11ff
4 changed files with 48 additions and 8 deletions

View File

@ -11,6 +11,8 @@
#import "SDImageCoder.h"
#import "SDImageCodersManager.h"
#import "SDImageFrame.h"
#import "UIImage+MemoryCacheCost.h"
#import "objc/runtime.h"
static CGFloat SDImageScaleFromPath(NSString *string) {
if (string.length == 0 || [string hasSuffix:@"/"]) return 1;
@ -426,3 +428,31 @@ static NSArray *SDBundlePreferredScales() {
}
@end
@interface SDAnimatedImage (MemoryCacheCost)
@end
@implementation SDAnimatedImage (MemoryCacheCost)
- (NSUInteger)sd_imageMemoryCost {
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_memoryCost));
if (value != nil) {
return value.unsignedIntegerValue;
}
CGImageRef imageRef = self.CGImage;
if (!imageRef) {
return 0;
}
NSUInteger bytesPerFrame = CGImageGetBytesPerRow(imageRef) * CGImageGetHeight(imageRef);
NSUInteger frameCount = 1;
if (self.isAllFramesLoaded) {
frameCount = self.animatedImageFrameCount;
}
frameCount = frameCount > 0 ? frameCount : 1;
NSUInteger cost = bytesPerFrame * frameCount;
return cost;
}
@end

View File

@ -82,13 +82,14 @@ typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) {
@property (assign, nonatomic) NSUInteger maxCacheSize;
/**
* The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory.
* The maximum "total cost" of the in-memory image cache. The cost function is the bytes size held in memory.
* @note The memory cost is bytes size in memory, but not simple pixels count. For common ARGB8888 image, one pixel is 4 bytes (32 bits).
* Defaults to 0. Which means there is no memory cost limit.
*/
@property (assign, nonatomic) NSUInteger maxMemoryCost;
/**
* The maximum number of objects the cache should hold.
* The maximum number of objects in-memory image cache should hold.
* Defaults to 0. Which means there is no memory count limit.
*/
@property (assign, nonatomic) NSUInteger maxMemoryCount;

View File

@ -11,12 +11,13 @@
@interface UIImage (MemoryCacheCost)
/**
The memory cache cost for specify image used by image cache. The cost function is the pixles count held in memory.
The memory cache cost for specify image used by image cache. The cost function is the bytes size held in memory.
If you set some associated object to `UIImage`, you can set the custom value to indicate the memory cost.
For `UIImage`, this method return the single frame pixles count when `image.images` is nil for static image. Retuen full frame pixels count when `image.images` is not nil for animated image.
For `NSImage`, this method return the single frame pixels count because `NSImage` does not store all frames in memory.
For `UIImage`, this method return the single frame bytes size when `image.images` is nil for static image. Retuen full frame bytes size when `image.images` is not nil for animated image.
For `NSImage`, this method return the single frame bytes size because `NSImage` does not store all frames in memory.
@note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods.
@note For custom animated class conforms to `SDAnimatedImage`, you can override this getter method in your subclass to return a more proper value instead, which representing the current frames' total bytes.
*/
@property (assign, nonatomic) NSUInteger sd_memoryCost;

View File

@ -8,14 +8,22 @@
#import "UIImage+MemoryCacheCost.h"
#import "objc/runtime.h"
#import "NSImage+Compatibility.h"
FOUNDATION_STATIC_INLINE NSUInteger SDMemoryCacheCostForImage(UIImage *image) {
CGImageRef imageRef = image.CGImage;
if (!imageRef) {
return 0;
}
NSUInteger bytesPerFrame = CGImageGetBytesPerRow(imageRef) * CGImageGetHeight(imageRef);
NSUInteger frameCount;
#if SD_MAC
return image.size.height * image.size.width;
frameCount = 1;
#elif SD_UIKIT || SD_WATCH
NSUInteger imageSize = image.size.height * image.size.width * image.scale * image.scale;
return image.images ? (imageSize * image.images.count) : imageSize;
frameCount = image.images.count > 0 ? image.images.count : 1;
#endif
NSUInteger cost = bytesPerFrame * frameCount;
return cost;
}
@implementation UIImage (MemoryCacheCost)