@@ -36,22 +36,35 @@ @implementation YYCache (SDAdditions)
3636 return nil ;
3737 }
3838
39- if ([context valueForKey: SDWebImageContextImageTransformer]) {
39+ id <SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
40+ if (transformer) {
4041 // grab the transformed disk image if transformer provided
41- id <SDImageTransformer> transformer = [context valueForKey: SDWebImageContextImageTransformer];
4242 NSString *transformerKey = [transformer transformerKey ];
4343 key = SDTransformedKeyForKey (key, transformerKey);
4444 }
4545
4646 // First check the in-memory cache...
4747 UIImage *image = [self .memoryCache objectForKey: key];
4848
49- if ((options & SDImageCacheDecodeFirstFrameOnly) && image.sd_isAnimated ) {
49+ if (image) {
50+ if (options & SDImageCacheDecodeFirstFrameOnly) {
51+ // Ensure static image
52+ Class animatedImageClass = image.class ;
53+ if (image.sd_isAnimated || ([animatedImageClass isSubclassOfClass: [UIImage class ]] && [animatedImageClass conformsToProtocol: @protocol (SDAnimatedImage)])) {
5054#if SD_MAC
51- image = [[NSImage alloc ] initWithCGImage: image.CGImage scale: image.scale orientation: kCGImagePropertyOrientationUp ];
55+ image = [[NSImage alloc ] initWithCGImage: image.CGImage scale: image.scale orientation: kCGImagePropertyOrientationUp ];
5256#else
53- image = [[UIImage alloc ] initWithCGImage: image.CGImage scale: image.scale orientation: image.imageOrientation];
57+ image = [[UIImage alloc ] initWithCGImage: image.CGImage scale: image.scale orientation: image.imageOrientation];
5458#endif
59+ }
60+ } else if (options & SDImageCacheMatchAnimatedImageClass) {
61+ // Check image class matching
62+ Class animatedImageClass = image.class ;
63+ Class desiredImageClass = context[SDWebImageContextAnimatedImageClass];
64+ if (desiredImageClass && ![animatedImageClass isSubclassOfClass: desiredImageClass]) {
65+ image = nil ;
66+ }
67+ }
5568 }
5669
5770 BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryMemoryData));
@@ -69,22 +82,48 @@ @implementation YYCache (SDAdditions)
6982 // 2. in-memory cache miss & diskDataSync
7083 BOOL shouldQueryDiskSync = ((image && options & SDImageCacheQueryMemoryDataSync) ||
7184 (!image && options & SDImageCacheQueryDiskDataSync));
72- void (^queryDiskBlock)(NSData *) = ^(NSData *diskData){
85+ void (^queryDiskBlock)(NSData *) = ^(NSData *diskData) {
7386 if (operation.isCancelled ) {
74- // do not call the completion if cancelled
87+ if (doneBlock) {
88+ doneBlock (nil , nil , SDImageCacheTypeNone);
89+ }
7590 return ;
7691 }
7792
7893 @autoreleasepool {
7994 UIImage *diskImage;
80- SDImageCacheType cacheType = SDImageCacheTypeDisk ;
95+ SDImageCacheType cacheType = SDImageCacheTypeNone ;
8196 if (image) {
8297 // the image is from in-memory cache, but need image data
8398 diskImage = image;
8499 cacheType = SDImageCacheTypeMemory;
85100 } else if (diskData) {
101+ cacheType = SDImageCacheTypeDisk;
86102 // decode image data only if in-memory cache missed
87103 diskImage = SDImageCacheDecodeImageData (diskData, key, options, context);
104+ if (diskImage) {
105+ // Check extended data
106+ NSData *extendedData = [YYDiskCache getExtendedDataFromObject: diskData];
107+ if (extendedData) {
108+ id extendedObject;
109+ if (@available (iOS 11 , tvOS 11 , macOS 10.13 , watchOS 4 , *)) {
110+ NSError *error;
111+ NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc ] initForReadingFromData: extendedData error: &error];
112+ unarchiver.requiresSecureCoding = NO ;
113+ extendedObject = [unarchiver decodeTopLevelObjectForKey: NSKeyedArchiveRootObjectKey error: &error];
114+ if (error) {
115+ NSLog (@" NSKeyedUnarchiver unarchive failed with error: %@ " , error);
116+ }
117+ } else {
118+ @try {
119+ extendedObject = [NSKeyedUnarchiver unarchiveObjectWithData: extendedData];
120+ } @catch (NSException *exception) {
121+ NSLog (@" NSKeyedUnarchiver unarchive failed with exception: %@ " , exception);
122+ }
123+ }
124+ diskImage.sd_extendedObject = extendedObject;
125+ }
126+ }
88127 if (diskImage) {
89128 NSUInteger cost = diskImage.sd_memoryCost ;
90129 [self .memoryCache setObject: diskImage forKey: key cost: cost];
@@ -108,7 +147,7 @@ @implementation YYCache (SDAdditions)
108147 queryDiskBlock (diskData);
109148 } else {
110149 // YYDiskCache's completion block is called in the global queue
111- [self .diskCache objectForKey: key withBlock: ^(NSString * _Nonnull key, NSObject < NSCoding> * _Nullable object) {
150+ [self .diskCache objectForKey: key withBlock: ^(NSString * _Nonnull key, id < NSObject , NSCoding > _Nullable object) {
112151 NSData *diskData = nil ;
113152 if ([object isKindOfClass: [NSData class ]]) {
114153 diskData = (NSData *)object;
@@ -120,6 +159,49 @@ @implementation YYCache (SDAdditions)
120159 return operation;
121160}
122161
162+ - (void )storeImageToDisk : (UIImage *)image imageData : (NSData *)imageData forKey : (NSString *)key completion : (SDWebImageNoParamsBlock)completionBlock {
163+ NSData *data = SDYYPluginCacheDataWithImageData (image, imageData);
164+ if (!data) {
165+ // SDImageCache does not remove object if `data` is nil
166+ if (completionBlock) {
167+ dispatch_async (dispatch_get_main_queue (), ^{
168+ completionBlock ();
169+ });
170+ }
171+ return ;
172+ }
173+ if (image) {
174+ // Check extended data
175+ id extendedObject = image.sd_extendedObject ;
176+ if ([extendedObject conformsToProtocol: @protocol (NSCoding)]) {
177+ NSData *extendedData;
178+ if (@available (iOS 11 , tvOS 11 , macOS 10.13 , watchOS 4 , *)) {
179+ NSError *error;
180+ extendedData = [NSKeyedArchiver archivedDataWithRootObject: extendedObject requiringSecureCoding: NO error: &error];
181+ if (error) {
182+ NSLog (@" NSKeyedArchiver archive failed with error: %@ " , error);
183+ }
184+ } else {
185+ @try {
186+ extendedData = [NSKeyedArchiver archivedDataWithRootObject: extendedObject];
187+ } @catch (NSException *exception) {
188+ NSLog (@" NSKeyedArchiver archive failed with exception: %@ " , exception);
189+ }
190+ }
191+ if (extendedData) {
192+ [YYDiskCache setExtendedData: extendedData toObject: data];
193+ }
194+ }
195+ }
196+ [self .diskCache setObject: data forKey: key withBlock: ^{
197+ if (completionBlock) {
198+ dispatch_async (dispatch_get_main_queue (), ^{
199+ completionBlock ();
200+ });
201+ }
202+ }];
203+ }
204+
123205- (void )storeImage : (UIImage *)image imageData : (NSData *)imageData forKey : (NSString *)key cacheType : (SDImageCacheType)cacheType completion : (SDWebImageNoParamsBlock)completionBlock {
124206 switch (cacheType) {
125207 case SDImageCacheTypeNone: {
@@ -131,49 +213,22 @@ - (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSStri
131213 case SDImageCacheTypeMemory: {
132214 NSUInteger cost = image.sd_memoryCost ;
133215 [self .memoryCache setObject: image forKey: key cost: cost];
216+ if (completionBlock) {
217+ completionBlock ();
218+ }
134219 }
135220 break ;
136221 case SDImageCacheTypeDisk: {
137222 dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0 ), ^{
138- NSData *data = SDYYPluginCacheDataWithImageData (image, imageData);
139- if (!data) {
140- // SDImageCache does not remove object if `data` is nil
141- if (completionBlock) {
142- dispatch_async (dispatch_get_main_queue (), ^{
143- completionBlock ();
144- });
145- }
146- }
147- [self .diskCache setObject: data forKey: key withBlock: ^{
148- if (completionBlock) {
149- dispatch_async (dispatch_get_main_queue (), ^{
150- completionBlock ();
151- });
152- }
153- }];
223+ [self storeImageToDisk: image imageData: imageData forKey: key completion: completionBlock];
154224 });
155225 }
156226 break ;
157227 case SDImageCacheTypeAll: {
158228 NSUInteger cost = image.sd_memoryCost ;
159229 [self .memoryCache setObject: image forKey: key cost: cost];
160230 dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0 ), ^{
161- NSData *data = SDYYPluginCacheDataWithImageData (image, imageData);
162- if (!data) {
163- // SDImageCache does not remove object if `data` is nil
164- if (completionBlock) {
165- dispatch_async (dispatch_get_main_queue (), ^{
166- completionBlock ();
167- });
168- }
169- }
170- [self .diskCache setObject: data forKey: key withBlock: ^{
171- if (completionBlock) {
172- dispatch_async (dispatch_get_main_queue (), ^{
173- completionBlock ();
174- });
175- }
176- }];
231+ [self storeImageToDisk: image imageData: imageData forKey: key completion: completionBlock];
177232 });
178233 }
179234 break ;
0 commit comments