Add the removal and status method for animated image preloading. Update the comments

This commit is contained in:
DreamPiggy 2018-03-03 17:08:57 +08:00
parent 5e09c6bf19
commit d49d7f7c0a
2 changed files with 33 additions and 37 deletions

View File

@ -54,13 +54,23 @@
// These methods are for SDAnimatedImage class only but not for SDWebImageAnimatedCoder.
@optional
/**
Preload all frame image to memory. Then later request can directly return the frame for index without decoding.
Pre-load all animated image frame into memory. Then later frame image request can directly return the frame for index without decoding.
This method may be called on background thread.
@note If the image is shared by lots of imageViews, preload all frames will reduce the CPU cost because the decoder may not need to keep re-entrant for randomly index access. But this will cause more memory usage.
@note If one image instance is shared by lots of imageViews, the CPU performance for large animated image will drop down because the request frame index will be random (not in order) and the decoder should take extra effort to keep it re-entrant. You can use this to reduce CPU usage if need. Attention this will consume more memory usage.
*/
- (void)preloadAllFrames;
/**
Unload all animated image frame from memory if are already pre-loaded. Then later frame image request need decoding. You can use this to free up the memory usage if need.
*/
- (void)unloadAllFrames;
/**
Returns a Boolean value indicating whether all animated image frames are already pre-loaded into memory.
*/
- (BOOL)isAllFramesLoaded;
/**
Initializes the image with an animated coder. You can use the coder to decode the image frame later.
@note Normally we use `initWithData:scale:` to create custom animated image class. So you can implement your custom class without our built-in coder.
@ -93,6 +103,7 @@
Current animated image format.
*/
@property (nonatomic, assign, readonly) SDImageFormat animatedImageFormat;
/**
Current animated image data, you can use this instead of CGImage to create another instance
*/
@ -106,13 +117,10 @@
*/
@property (nonatomic, readonly) CGFloat scale;
/**
Preload all frame image to memory. Then later request can directly return the frame for index without decoding.
The preloaded animated image frames will be removed when receiving memory warning.
@note If the image is shared by lots of imageViews, preload all frames will reduce the CPU cost because the decoder may not need to keep re-entrant for randomly index access. But this will cause more memory usage.
@note Once preload the frames into memory, there is no huge difference on performance between this and UIImage's `animatedImageWithImages:duration:`. But UIImage's animation have some issue such like blanking or frame restarting working with `UIImageView`. It's recommend to use only if need.
*/
// By default, animated image frames are returned by decoding just in time without keeping into memory. But you can choose to preload them into memory as well, See the decsription in `SDAnimatedImage` protocol.
// After preloaded, there is no huge difference on performance between this and UIImage's `animatedImageWithImages:duration:`. But UIImage's animation have some issues such like blanking and pausing during segue when using in `UIImageView`. It's recommend to use only if need.
- (void)preloadAllFrames;
- (void)unloadAllFrames;
@property (nonatomic, assign, readonly, getter=isAllFramesLoaded) BOOL allFramesLoaded;
@end

View File

@ -199,8 +199,8 @@ static NSArray *SDBundlePreferredScales() {
@property (nonatomic, strong) id<SDWebImageAnimatedCoder> coder;
@property (nonatomic, assign, readwrite) SDImageFormat animatedImageFormat;
@property (atomic, copy) NSArray<SDWebImageFrame *> *preloadAnimatedImageFrames;
@property (nonatomic, assign) BOOL animatedImageFramesPreloaded;
@property (atomic, copy) NSArray<SDWebImageFrame *> *loadedAnimatedImageFrames; // Mark as atomic to keep thread-safe
@property (nonatomic, assign, getter=isAllFramesLoaded) BOOL allFramesLoaded;
@end
@ -209,21 +209,6 @@ static NSArray *SDBundlePreferredScales() {
@dynamic scale; // call super
#endif
#pragma mark - Dealloc & Memory warning
- (void)dealloc {
#if SD_UIKIT
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#endif
}
- (void)didReceiveMemoryWarning:(NSNotification *)notification {
if (self.animatedImageFramesPreloaded) {
self.preloadAnimatedImageFrames = nil;
self.animatedImageFramesPreloaded = NO;
}
}
#pragma mark - UIImage override method
+ (instancetype)imageNamed:(NSString *)name {
#if __has_include(<UIKit/UITraitCollection.h>)
@ -363,7 +348,7 @@ static NSArray *SDBundlePreferredScales() {
#pragma mark - Preload
- (void)preloadAllFrames {
if (!self.animatedImageFramesPreloaded) {
if (!self.isAllFramesLoaded) {
NSMutableArray<SDWebImageFrame *> *frames = [NSMutableArray arrayWithCapacity:self.animatedImageFrameCount];
for (size_t i = 0; i < self.animatedImageFrameCount; i++) {
UIImage *image = [self animatedImageFrameAtIndex:i];
@ -371,12 +356,15 @@ static NSArray *SDBundlePreferredScales() {
SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; // through the image should be nonnull, used as nullable for `animatedImageFrameAtIndex:`
[frames addObject:frame];
}
self.preloadAnimatedImageFrames = frames;
self.animatedImageFramesPreloaded = YES;
#if SD_UIKIT
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
#endif
self.loadedAnimatedImageFrames = frames;
self.allFramesLoaded = YES;
}
}
- (void)unloadAllFrames {
if (self.isAllFramesLoaded) {
self.loadedAnimatedImageFrames = nil;
self.allFramesLoaded = NO;
}
}
@ -422,8 +410,8 @@ static NSArray *SDBundlePreferredScales() {
if (index >= self.animatedImageFrameCount) {
return nil;
}
if (self.animatedImageFramesPreloaded) {
SDWebImageFrame *frame = [self.preloadAnimatedImageFrames objectAtIndex:index];
if (self.isAllFramesLoaded) {
SDWebImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index];
return frame.image;
}
return [self.coder animatedImageFrameAtIndex:index];
@ -433,8 +421,8 @@ static NSArray *SDBundlePreferredScales() {
if (index >= self.animatedImageFrameCount) {
return 0;
}
if (self.animatedImageFramesPreloaded) {
SDWebImageFrame *frame = [self.preloadAnimatedImageFrames objectAtIndex:index];
if (self.isAllFramesLoaded) {
SDWebImageFrame *frame = [self.loadedAnimatedImageFrames objectAtIndex:index];
return frame.duration;
}
return [self.coder animatedImageDurationAtIndex:index];