@@ -36,22 +36,35 @@ @implementation YYCache (SDAdditions)
36
36
return nil ;
37
37
}
38
38
39
- if ([context valueForKey: SDWebImageContextImageTransformer]) {
39
+ id <SDImageTransformer> transformer = context[SDWebImageContextImageTransformer];
40
+ if (transformer) {
40
41
// grab the transformed disk image if transformer provided
41
- id <SDImageTransformer> transformer = [context valueForKey: SDWebImageContextImageTransformer];
42
42
NSString *transformerKey = [transformer transformerKey ];
43
43
key = SDTransformedKeyForKey (key, transformerKey);
44
44
}
45
45
46
46
// First check the in-memory cache...
47
47
UIImage *image = [self .memoryCache objectForKey: key];
48
48
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)])) {
50
54
#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 ];
52
56
#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];
54
58
#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
+ }
55
68
}
56
69
57
70
BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryMemoryData));
@@ -69,22 +82,48 @@ @implementation YYCache (SDAdditions)
69
82
// 2. in-memory cache miss & diskDataSync
70
83
BOOL shouldQueryDiskSync = ((image && options & SDImageCacheQueryMemoryDataSync) ||
71
84
(!image && options & SDImageCacheQueryDiskDataSync));
72
- void (^queryDiskBlock)(NSData *) = ^(NSData *diskData){
85
+ void (^queryDiskBlock)(NSData *) = ^(NSData *diskData) {
73
86
if (operation.isCancelled ) {
74
- // do not call the completion if cancelled
87
+ if (doneBlock) {
88
+ doneBlock (nil , nil , SDImageCacheTypeNone);
89
+ }
75
90
return ;
76
91
}
77
92
78
93
@autoreleasepool {
79
94
UIImage *diskImage;
80
- SDImageCacheType cacheType = SDImageCacheTypeDisk ;
95
+ SDImageCacheType cacheType = SDImageCacheTypeNone ;
81
96
if (image) {
82
97
// the image is from in-memory cache, but need image data
83
98
diskImage = image;
84
99
cacheType = SDImageCacheTypeMemory;
85
100
} else if (diskData) {
101
+ cacheType = SDImageCacheTypeDisk;
86
102
// decode image data only if in-memory cache missed
87
103
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
+ }
88
127
if (diskImage) {
89
128
NSUInteger cost = diskImage.sd_memoryCost ;
90
129
[self .memoryCache setObject: diskImage forKey: key cost: cost];
@@ -108,7 +147,7 @@ @implementation YYCache (SDAdditions)
108
147
queryDiskBlock (diskData);
109
148
} else {
110
149
// 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) {
112
151
NSData *diskData = nil ;
113
152
if ([object isKindOfClass: [NSData class ]]) {
114
153
diskData = (NSData *)object;
@@ -120,6 +159,49 @@ @implementation YYCache (SDAdditions)
120
159
return operation;
121
160
}
122
161
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
+
123
205
- (void )storeImage : (UIImage *)image imageData : (NSData *)imageData forKey : (NSString *)key cacheType : (SDImageCacheType)cacheType completion : (SDWebImageNoParamsBlock)completionBlock {
124
206
switch (cacheType) {
125
207
case SDImageCacheTypeNone: {
@@ -131,49 +213,22 @@ - (void)storeImage:(UIImage *)image imageData:(NSData *)imageData forKey:(NSStri
131
213
case SDImageCacheTypeMemory: {
132
214
NSUInteger cost = image.sd_memoryCost ;
133
215
[self .memoryCache setObject: image forKey: key cost: cost];
216
+ if (completionBlock) {
217
+ completionBlock ();
218
+ }
134
219
}
135
220
break ;
136
221
case SDImageCacheTypeDisk: {
137
222
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];
154
224
});
155
225
}
156
226
break ;
157
227
case SDImageCacheTypeAll: {
158
228
NSUInteger cost = image.sd_memoryCost ;
159
229
[self .memoryCache setObject: image forKey: key cost: cost];
160
230
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];
177
232
});
178
233
}
179
234
break ;
0 commit comments